Files
bij/docs/migration/admin-rebuild.md
2026-04-21 05:59:39 +07:00

15 KiB

Admin rebuild (CI4 + TailAdmin + API)

Ini bukan migrasi modul admin HMVC CodeIgniter 3. Panel admin dibangun ulang di CodeIgniter 4 dengan UI Tailwind (aset TailAdmin di public/assets/tailadmin/) dan tanpa query database langsung dari controller web admin. Semua data modul Pegawai, Presensi, Laporan ringkasan, Dashboard beranda, dan Cuti diambil lewat API internal (/api/admin/* dan untuk profil/berita tetap /api/mobile/*).

Prinsip

  • Controller di app/Controllers/Admin/ hanya memanggil ApiClient → HTTP ke aplikasi yang sama.
  • Tidak menyalin HMVC CI3, tidak memakai Grocery CRUD.
  • Akses database untuk fitur admin terpusat di app/Services/Admin/AdminApiService.php + model CI4 (PegawaiModel, dll.).
  • Respons API diseragamkan: { "status": 0|1, "pesan": "...", "data": ... } (selaras API mobile).

RBAC (peran & fitur)

  • Konfigurasi: app/Config/AdminAccess.php memetakan nama fitur → daftar slug grup Ion yang boleh. Daftar kosong artinya semua admin yang sudah login (setelah authadmin).
  • Helper: app/Helpers/rbac_helper.phphasRole(), hasAnyRole(), canAccess($feature). Membaca admin_ion_groups dari sesi (nama grup, perbandingan case-insensitive).
  • Kapan aturan Ion dipakai: jika admin_auth_source === 'admin_users'. Login pegawai saja (tanpa grup Ion di sesi) mempertahankan perilaku lama: canAccess mengizinkan semua fitur yang punya daftar grup (kompatibel token proxy). Ini selaras kebutuhan token API pegawai untuk semua endpoint admin.
  • Jika admin_users tetapi grup kosong: fitur yang membutuhkan grup tertentu → ditolak (menu disembunyikan, enforceAccess redirect dengan flash).
  • Controller web: BaseAdminController::enforceAccess('nama_fitur') di awal aksi; gagal → redirect ke /admin dengan flash error, atau JSON 403 untuk AJAX.
  • View: hanya memanggil canAccess('...')tanpa menuliskan nama peran di view; semua mapping ada di AdminAccess.

Pemetaan fitur ↔ grup (sama ci_bootstrap.php CI3)

Fitur (canAccess) Grup yang boleh
dashboard (semua login admin)
presensi (semua)
perusahaan (semua)
pegawai webmaster, hrd
cuti webmaster, hrd
laporan webmaster, hrd
panel webmaster
utilitas webmaster
apk_link webmaster, penyelenggara, operator_cabang, operator_ranting, operator_sekolah, admin_soal, operator_soal
references (semua login admin) — referensi form pegawai

Autentikasi web

  1. GET/POST /admin/loginAuth::attempt urutannya:
    • Pegawai: POST /api/mobile/login (MD5 password, tabel pegawai).
    • Jika gagal: admin_users (Ion Auth CI3): password_verify terhadap bcrypt/hash di kolom password, active = 1. Jika sukses, sistem menerbitkan token API dengan memakai pegawai proxy (lihat bawah) dan menyimpan token yang sama di sesi admin_mobile_token. Sesi juga menyimpan admin_auth_source = pegawai | admin_users.
  2. Data Ion Auth di DB: admin_users, admin_groups, admin_users_groups. Login admin_users wajib punya minimal satu baris di admin_users_groups bila tabel itu ada — tanpa grup, login ditolak.
  3. Proxy token (login admin_users): API hanya mengenali token di pegawai. Setelah Ion Auth sukses, token ditulis ke pegawai proxy: ADMIN_LOGIN_PROXY_PEGAWAI_ID (.env), lalu pegawai pertama super_akses = 'true', lalu id_pegawai terkecil. Untuk akun hanya HRD, bisa set ADMIN_LOGIN_PROXY_PEGAWAI_ID_HRD.
  4. Sesi menyimpan admin_ion_user_id dan admin_ion_groups (nama grup) bila sumber admin_users — dipakai RBAC + header.
  5. GET /admin/logout — di luar filter.
  6. Rute admin/* lain memakai filter authadmin: tanpa token sesi → redirect ke login (atau JSON 401 untuk AJAX).

API admin (/api/admin/*)

Parameter token (sama dengan admin_mobile_token di sesi panel) tetap dikirim lewat query GET, field POST, atau header X-Admin-Tokenstruktur token untuk klien mobile tidak diubah (/api/mobile/* tidak tersentuh).

Admin API Security

  • Sesi panel wajib: setiap /api/admin/* memverifikasi bahwa permintaan membawa cookie sesi yang valid dan berisi admin_mobile_token, serta bahwa token di URL/body/header sama persis dengan nilai di sesi. Tanpa itu, respons 401 dengan JSON { "status": 0, "pesan": "Unauthorized" } — sehingga curl/Postman hanya dengan ?token= pegawai (tanpa cookie login admin) ditolak.
  • RBAC di API: setelah sesi valid, BaseAdminApiController::requireAdminApiAccess('fitur') memanggil canAccess() (sama Config\AdminAccess + admin_ion_groups seperti UI). Gagal → 403 dengan { "status": 0, "pesan": "Forbidden" }.
  • Penerusan cookie internal: ApiClient::getAdmin / postAdmin meneruskan header Cookie dari permintaan browser ke hit HTTP internal, dan memanggil session_write_close() sebelum CURL agar menghindari deadlock file session (sub-request dapat membuka sesi yang sama).
  • Logging teks: percobaan ditolak dicatat ke log aplikasi (log_message('warning', ...)) dengan alasan singkat, alamat IP, path URI, dan timestamp ISO-8601; lihat juga Audit Logging System di bawah untuk rekaman DB.
  • Token admin terpisah: tidak wajib; tidak mengganti model sesi saat ini.

Audit Logging System

  • Tabel: admin_activity_logs (migrasi app/Database/Migrations/2026-04-18-140000_CreateAdminActivityLogs.php). Kolom: id, admin_user, action, endpoint, payload (JSON teks), ip_address, user_agent, auth_source, roles_json (JSON grup Ion dari sesi), outcome (success | unauthorized | forbidden), created_at.
  • Layanan: app/Services/AdminAuditService.php — metode log(string $action, array $payload = []). Menyisipkan konteks HTTP (_http), panel (_session_panel: sumber auth, grup Ion, indikator token admin), ringkasan actor pegawai (dari token API), dan payload bisnis. Nilai sensitif (password, token, dll.) diganti [redacted].
  • Integrasi API: setelah requireAdminApiAccess sukses, setiap endpoint di app/Controllers/Api/Admin/* memanggil auditAuthorized() di BaseAdminApiController dengan nama aksi konsisten (api.admin.cuti.approve, api.admin.pegawai.update, …). Mutasi penting (approve/reject cuti, create/update/delete/reset pegawai) menyertakan ID / field ringkas di payload.
  • Keamanan: percobaan Unauthorized / Forbidden juga ditulis lewat log() dengan __outcome = unauthorized | forbidden dan aksi api.admin.security.unauthorized / api.admin.security.forbidden.
  • Performa: insert sinkron ringan; payload dibatasi panjang; jika tabel belum ada, tulisan dilewati (debug log) agar tidak memutus deploy.
Metode Path Keterangan
GET /api/admin/references Dropdown: jabatan, unit_kerja, golongan, kantor, jadwal
GET /api/admin/dashboard Statistik beranda + antrian cuti Waiting (20 baris + total)
GET /api/admin/pegawai Daftar pegawai + pagination (page, per_page, q)
GET /api/admin/pegawai/{id} Detail pegawai
POST /api/admin/pegawai/create Tambah pegawai
POST /api/admin/pegawai/update Body termasuk id_pegawai
POST /api/admin/pegawai/delete Body id_pegawai
POST /api/admin/pegawai/reset_password Body id_pegawai
GET /api/admin/presensi Daftar presensi (tanggal_dari, tanggal_sampai, page, per_page, q nama/NIP)
GET /api/admin/presensi/{id} Detail presensi
GET /api/admin/laporan Ringkasan agregat (dari, sampai)
GET /api/admin/cuti Daftar cuti (status kosong=semua, Waiting, Approve, Rejected, Cancelled, page, per_page)
GET /api/admin/cuti/{id} Detail cuti + daftar file dokumen
POST /api/admin/cuti/approve Body id_cuti
POST /api/admin/cuti/reject Body id_cuti, alasan_tolak
GET /api/admin/laporan/cuti Laporan cuti rentang (dari, sampai)
GET/POST /api/admin/company/* Master perusahaan (kantor, unit, golongan, jabatan, berita)
GET/POST `/api/admin/presensi/dilapangan lembur
GET/POST `/api/admin/panel/users groups
GET/POST /api/admin/backup* Daftar / jalankan / hapus file backup SQL

Controller API: app/Controllers/Api/Admin/*. Rute di app/Config/Routes.php grup api/admin. Dasar kelas: BaseAdminApiController (sesi + ikatan token + RBAC per fitur).

Rute web admin

Path Fungsi
/admin/login, POST login Login
/admin/logout Keluar
/admin Dashboard (API dashboard + profil/berita mobile)
/admin/pegawai Daftar pegawai
/admin/pegawai/create, POST store Tambah
/admin/pegawai/edit/{id}, POST update/{id} Edit
POST pegawai/delete/{id} Hapus
POST pegawai/reset/{id} Reset password
/admin/presensi Daftar + filter tanggal + cari nama/NIP
/admin/presensi/detail/{id} Detail
/admin/presensi/lapanganaktivitas Master alat presensi (dilapangan, lembur, libur, jadwal, aktivitas)
/admin/perusahaan/kantorberita CRUD master perusahaan
/admin/laporan Ringkasan + filter tanggal
/admin/laporan/cuti Tabel cuti rentang tanggal
/admin/panel/users, create, reset/{id} Pengguna admin Ion
/admin/util/backup Backup DB (file di writable/admin_db_backup/)
/admin/cuti Daftar cuti + filter status
/admin/cuti/detail/{id} Detail + approve/reject
POST /admin/cuti/approve/{id} Setujui
POST /admin/cuti/reject/{id} Tolak + alasan

ApiClient & BaseAdminController

  • getAdmin / postAdmin — ke /api/admin/* dengan token otomatis + penerusan Cookie untuk sesi panel.
  • BaseAdminController::enforceAccess($feature) — RBAC fitur di UI web.

Konfigurasi

app.baseURL di .env harus benar agar panggilan internal CURLRequest berhasil.

Modul vs CI3 — parity & celah

Sudah mendekati CI3 (usable):

  • Dashboard beranda: kartu pegawai/presensi/cuti hari ini, bar ringkasan, tabel permohonan cuti Waiting + aksi cepat (bila canAccess('cuti')).
  • Cuti admin: daftar, detail, approve/reject (status Approve / Rejected + alasan_tolak), dokumen di assets/uploads/dokcuti/.
  • Pegawai, presensi (dengan badge status baris), laporan ringkasan.

Masih berbeda / lanjutan:

  • Lingkup data di AdminApiService tetap mengikuti baris pegawai yang memiliki token (proxy); siapa boleh memanggil endpoint kini dijaga sesi + RBAC seperti UI.
  • Laporan keuangan CI3 (piutang, penjualan, laba, dll.) tidak di-port ke modul admin CI4 ini.
  • Cetak khusus seperti PHPExcel di CI3 diganti dengan tabel web + cetak browser / integrasi via endpoint JSON bila diperlukan.

Peta halaman CI3 (discovery)

Daftar lengkap URL, controller, method, peran, dan pemetaan ke CI4 ada di docs/migration/admin-pages-map.md. File itu menjadi acuan agar tidak ada halaman CI3 yang “hilang” dari checklist tanpa sengaja.

UI shell TailAdmin (dashboard)

Tujuan: tampilan konsisten seperti demo TailAdmin (sidebar terang, border gray-200, kartu rounded-2xl, header sticky, tabel dengan header abu), tanpa memuat public/assets/tailadmin/css/style.css mentah di browser — file itu memakai @import "tailwindcss" / @apply dan membutuhkan build npm, bukan CSS siap pakai. Untuk kelas utilitas dari markup PHP, tetap memakai Tailwind CDN di layouts/main.php + layouts/auth.php; aset lokal yang dipakai: Font Awesome (fa-7.1.0-web/css/all.min.css) dan logo brand public/assets/images/bpr-logo.png (sidebar + halaman login).

Layout admin (layouts/main.php):

  • #admin-shell: flex penuh tinggi viewport, latar bg-gray-50.
  • Sidebar (layouts/sidebar.php): lebar 290px, putih, border kanan; menu mengikuti ci_bootstrap.php CI3; teks judul memakai kelas sidebar-text / nav-section-label agar bisa disembunyikan saat mode sempit desktop (sidebar-narrow + localStorage).
  • Mobile (< lg): sidebar transform: translateX(-100%); tombol hamburger di header membuka kelas mobile-sidebar-open pada #admin-shell; overlay #sidebar-overlay menutup panel ketika diketuk.
  • Desktop: tombol kolom di header men-toggle sidebar-narrow (lebar sidebar 90px, label disembunyikan).
  • Header (layouts/header.php): sticky, flash message, info sesi singkat.
  • Footer (layouts/footer.php): strip tipis di bawah konten scroll.

Struktur view modul (rapi):

Modul Path view
Beranda app/Views/admin/dashboard/index.php
Login app/Views/admin/auth/login.php
Pegawai app/Views/admin/pegawai/index.php, form.php
Presensi app/Views/admin/presensi/index.php, detail.php
Cuti app/Views/admin/cuti/index.php, detail.php
Laporan app/Views/admin/laporan/index.php, laporan/cuti.php
Perusahaan app/Views/admin/perusahaan/*.php
Presensi (alat) app/Views/admin/presensi/lapangan.php, lembur.php, libur.php, jadwal.php, aktivitas.php
Panel app/Views/admin/panel/users.php, user_create.php, user_reset.php
Utilitas app/Views/admin/util/backup.php

Semua halaman admin di atas memakai <?= $this->extend('layouts/main') ?> (login memakai layouts/auth).

Halaman selesai vs sisa (web admin)

Selesai (parity operasional harian + UI TailAdmin):

  • Beranda / dashboard (/admin)
  • Data presensi + detail + pencarian (/admin/presensi, detail)
  • Presensi: tugas luar/lapangan, lembur, management jadwal, hari libur, rekaman aktivitas
  • Perusahaan: lokasi kerja (kantor), unit kerja, jabatan, golongan, berita/pengumuman
  • Data pegawai + form tambah/edit + hapus + reset password (/admin/pegawai, …)
  • Data cuti + detail approve/reject (/admin/cuti, detail)
  • Ringkasan laporan (/admin/laporan) + laporan cuti rentang (/admin/laporan/cuti, cetak via browser)
  • Panel: daftar pengguna admin Ion, tambah pengguna (bukan webmaster), reset password
  • Utilitas: daftar backup SQL, jalankan backup, unduh, hapus file (writable/admin_db_backup/)
  • Login (/admin/login)

Belum di-port dari CI3 (sengaja / luar cakupan modul ini):

  • Laporan modul keuangan (jatuhtempo, penjualan, laba, cetak terkait)
  • Panel: kelola grup (admin_user_group), halaman profil/ubah password akun admin terpisah (bisa memakai alur pegawai/API)
  • Utilitas: restore database dari file (hanya backup + unduh + hapus)
  • Unggah foto berita lewat form file (CI4 saat ini: isi nama file manual jika file sudah di server)

Catatan parity UX

  • Urutan dan label menu utama mengikuti sidemenu / menu CI3; submenu yang sudah di CI4 memakai tautan aktif di layouts/sidebar.php.
  • Tombol primer diseragamkan ke biru (bg-blue-600) seperti aksen umum TailAdmin; sekunder tetap border gray + putih.
  • Tabel: header bg-gray-50, border baris divide-gray-100, footer pagination dengan strip bg-gray-50/80.