Initial commit BIJ CI4
This commit is contained in:
201
docs/migration/LAPORAN-MIGRASI-CI3-KE-CI4.md
Normal file
201
docs/migration/LAPORAN-MIGRASI-CI3-KE-CI4.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Laporan persiapan migrasi CI3 → CI4
|
||||
|
||||
**Sumber (tidak diubah):** `C:\laragon\www\bij-migration\bij.mwp.co.id`
|
||||
**Target:** `C:\laragon\www\bij-migration\bij.mwp.co.id-ci4` (CodeIgniter 4.7.x via `appstarter`)
|
||||
|
||||
**Indeks dokumen terbaru:** mulai dari [README.md](README.md) (controllers, models, routes, auth, risks, json_api_map, ROADMAP).
|
||||
|
||||
API mobile **sudah di-port** ke `App\Services\Mobile\MobileJsonService` + `MobileJsonController`; admin memakai layout dasar + aset TailAdmin di `public/assets/tailadmin/`.
|
||||
|
||||
Dokumen ini tetap memuat ringkasan awal + checklist; detail teknis dipindah ke file tema di folder yang sama.
|
||||
|
||||
---
|
||||
|
||||
## 1. Peta komponen CI3
|
||||
|
||||
### 1.1 Controller (`application/controllers/`)
|
||||
|
||||
| File | Peran singkat |
|
||||
|------|----------------|
|
||||
| `Json.php` | API JSON untuk aplikasi mobile (presensi, cuti, profil, dll.); query DB langsung di controller |
|
||||
| `Site.php` | Frontend ringkas: redirect, halaman login, `login_auth` (Ion Auth) |
|
||||
| `Cli.php` | Perintah CLI |
|
||||
| `Errors.php` | Penanganan error |
|
||||
|
||||
Routing default: `application/config/routes.php` mengarah ke `site`; endpoint `Json` mengikuti konvensi CI3 `controller/method` (mis. `json/login`).
|
||||
|
||||
### 1.2 Model (`application/models/`)
|
||||
|
||||
| Model | Konteks tipikal |
|
||||
|-------|-------------------|
|
||||
| `User_model.php`, `Group_model.php`, `Admin_user_model.php`, `Api_key_model.php` | Pola CI Bootstrap / admin & API (bukan dipakai langsung oleh `Json.php` mobile) |
|
||||
|
||||
Catatan: logika mobile di `Json.php` **tidak** memakai model ini; data diambil lewat `$this->db` di controller.
|
||||
|
||||
### 1.3 Routes (`application/config/routes.php`)
|
||||
|
||||
- `default_controller` = `site`
|
||||
- Pola **CI Bootstrap 3**: prefix bahasa `^(\w{2})/(.*)$`, routing REST `api/(:any)/(:num)` → modul `api`
|
||||
- Tidak ada definisi eksplisit per method untuk `Json`; mengandalkan routing default CI3.
|
||||
|
||||
### 1.4 Modul HMVC (`application/modules/`)
|
||||
|
||||
| Modul | Isi penting |
|
||||
|-------|-------------|
|
||||
| **admin** | `Home`, `Pegawai`, `Presensi`, `Perusahaan`, `Laporan`, `Panel`, `Util`, `Errors`; views + Grocery CRUD / laporan |
|
||||
| **api** | `Home`, `Swagger`, `Errors`; library `Jwt_client.php` (Firebase JWT)—**alur mobile `Json.php` memakai token string di tabel `pegawai`, bukan JWT ini** |
|
||||
| **adminlte** | `Widget.php`—komponen UI |
|
||||
|
||||
HMVC memakai **MX_Controller** (lihat `application/core/MY_Controller.php`).
|
||||
|
||||
### 1.5 Auth
|
||||
|
||||
- **Web admin / site:** **Ion Auth** (`ion_auth` di autoload), login di `Site::login_auth`, pembatasan halaman lewat `mPageAuth` + `ion_auth->in_group()` di `MY_Controller`.
|
||||
- **Mobile (`Json.php`):** autentikasi **stateless token** disimpan kolom `pegawai.token`, password **MD5** di tabel; tidak memakai Ion Auth di controller ini.
|
||||
|
||||
### 1.6 Helper & library custom (ringkas)
|
||||
|
||||
**Helpers** (`application/helpers/`): `MY_string_helper.php`, `MY_url_helper.php`, `MY_directory_helper.php`.
|
||||
|
||||
**Libraries** (akar `application/libraries/`, selain vendor besar):
|
||||
|
||||
- `Data_importer.php`, `Form_builder.php`, `System_message.php`
|
||||
- `MY_Email.php`, `MY_Form_validation.php`, `MY_Pagination.php`
|
||||
- `PHPExcel.php` + pohon **PHPExcel** (usang; di CI4 ganti **PhpSpreadsheet**)
|
||||
|
||||
**Autoload** (`application/config/autoload.php`): paket `ion_auth`, `grocery_crud`, `image_crud`, `rest_server`; library `database`, `ion_auth`, `form_validation`.
|
||||
|
||||
**Third party** (indikasi): Ion Auth, Grocery CRUD, Image CRUD, REST server (lihat folder `application/third_party/` bila perlu detail).
|
||||
|
||||
---
|
||||
|
||||
## 2. Audit `application/controllers/Json.php`
|
||||
|
||||
### 2.1 Daftar method publik
|
||||
|
||||
| Method | Kategori |
|
||||
|--------|----------|
|
||||
| `index` | Penolakan akses |
|
||||
| `login_w_token` | Login / token |
|
||||
| `login` | Login / token |
|
||||
| `profil` | Pegawai / mobile |
|
||||
| `save_cuti` | Cuti + upload / mobile |
|
||||
| `batalkan_cuti` | Cuti / mobile |
|
||||
| `save_aktifitas` | Aktivitas + upload / mobile |
|
||||
| `save_masuk` | Presensi + geo + foto / mobile |
|
||||
| `save_pulang` | Presensi + geo + foto / mobile |
|
||||
| `save_istirahat` | Presensi / mobile |
|
||||
| `presensi_today` | Presensi / mobile |
|
||||
| `presensi` | Presensi / mobile |
|
||||
| `daftar_today` | Presensi / daftar rekan / mobile |
|
||||
| `berita` | Konten / mobile |
|
||||
| `cuti` | Cuti / mobile |
|
||||
| `lembur` | Lembur / mobile |
|
||||
| `libur` | Master libur / mobile |
|
||||
| `aktifitas` | Aktivitas / mobile |
|
||||
| `save_pp` | Profil foto / mobile |
|
||||
| `save_password` | Auth password / mobile |
|
||||
|
||||
Private: `generateRandomString`, `utf8ize`.
|
||||
|
||||
### 2.2 Login, token, pegawai, endpoint mobile
|
||||
|
||||
- **Login / token:** `login`, `login_w_token` (semua method lain memakai `token` POST untuk identitas pegawai).
|
||||
- **Pegawai:** `profil`, `save_pp`, `save_password`; seluruh alur memuat baris `pegawai` lewat token.
|
||||
- **Endpoint mobile (khas app):** semua di atas kecuali `index`; pola respons JSON + header `Access-Control-Allow-Origin: *` (CORS permisif).
|
||||
|
||||
### 2.3 Query langsung ke database
|
||||
|
||||
Seluruh file memakai **Active Record / query builder CI3** (`$this->db->...`) **di dalam controller**—tidak lewat model. Setiap method melakukan satu atau lebih: `from`, `where`, `get`, `insert`, `update`, `join`, dll. Tabel yang muncul: antara lain `pegawai`, `kantor`, `jabatan`, `unit_kerja`, `lembur`, `dilapangan`, `libur`, `cuti`, `jadwal`, `presensi`, `berita`, `cuti_dokumen`, `aktifitas_harian`.
|
||||
|
||||
### 2.4 Refactor besar yang disarankan
|
||||
|
||||
1. **Keamanan:** password **MD5**; token prediktabil (bagian `md5(id_pegawai)` + random); token disimpan plain di DB; **tanpa rate limiting** di controller.
|
||||
2. **Arsitektur:** pindahkan query ke **Model** / **Repository** / **Service**; controller hanya HTTP + validasi.
|
||||
3. **Upload:** base64 → file via helper `file`; path relatif `./assets/uploads/...`—di CI4 gunakan `Writable`/filesystem config, validasi MIME/size, nama file aman.
|
||||
4. **`utf8ize` memakai `utf8_encode()`** — perilaku usang/deprecated di PHP modern; sebaiknya konsisten **UTF-8** dari DB dan `json_encode` dengan flag yang tepat.
|
||||
5. **`daftar_today`:** tanggal di-inline ke string join (`date("Y-m-d")`)—risiko konsistensi; sebaiknya **binding parameter** / query builder terpisah.
|
||||
6. **`save_pulang`:** variabel toleransi memakai field `toleransi_terlambat` untuk batas pulang—perlu verifikasi apakah itu maksud bisnis atau bug (copy-paste dari masuk).
|
||||
7. **CORS `*`** + POST form-style: tinjau ulang untuk produksi (origin spesifik, HTTPS, CSRF untuk web—mobile biasanya token header).
|
||||
|
||||
Detail baris-per-baris ada di file pendamping `audit-json-controller.md` (folder yang sama).
|
||||
|
||||
---
|
||||
|
||||
## 3. Komponen: pindah langsung vs tulis ulang vs ditinggalkan
|
||||
|
||||
### 3.1 Bisa dipindahkan / diadaptasi dengan effort kecil–sedang
|
||||
|
||||
- Pola respons JSON `{ status, pesan, ... }` — pertahankan sementara untuk kompatibilitas klien mobile.
|
||||
- Struktur query bisnis (jadwal harian, insert `presensi` harian) — logika bisa dipindah ke service dengan sedikit penyesuaian API CI4 DB.
|
||||
- Helper custom yang murni string/url — port bertahap ke helper CI4 atau class util.
|
||||
|
||||
### 3.2 Harus ditulis ulang (disarankan)
|
||||
|
||||
- **Autentikasi mobile:** ganti MD5 → `password_hash` / verifikasi modern; token → **JWT** atau session server + refresh; invalidasi token.
|
||||
- **Seluruh lapisan akses data** untuk API mobile — model CI4, validasi input, transaction di operasi multi-tabel.
|
||||
- **Ion Auth + HMVC admin** — di CI4 umumnya modul terpisah atau admin berdiri sendiri; tidak ada port 1:1 HMVC MX.
|
||||
- **PHPExcel** — ganti **PhpSpreadsheet**.
|
||||
- **Grocery CRud / Image Crud** — evaluasi CI4 admin scaffold atau CRUD custom / paket modern.
|
||||
|
||||
### 3.3 Sebaiknya ditinggalkan atau diganti
|
||||
|
||||
- **PHPExcel** sebagai dependensi jangka panjang.
|
||||
- **CORS `*`** di API sensitif data kepegawaian.
|
||||
- Duplikasi besar potongan “decode base64 + write_file + insert DB” di banyak method — ganti satu **UploadService** + policy keamanan.
|
||||
|
||||
---
|
||||
|
||||
## 4. Struktur di target CI4 (aman, tanpa ubah vendor framework)
|
||||
|
||||
- `app/Controllers/Api/MobileJsonController.php` — endpoint API mobile.
|
||||
- `app/Services/Mobile/MobileJsonService.php` — port logika dari `Json.php`.
|
||||
- `app/Libraries/LegacyUtf8Encoder.php` — setara `utf8ize` untuk string ISO-8859-1.
|
||||
- `app/Config/Routes.php` — grup `api/mobile/*` dan alias **`json/*`**.
|
||||
- `app/Controllers/Admin/Dashboard.php` + `app/Views/layouts/*`, `app/Views/pages/dashboard.php` — foundation admin + TailAdmin assets di `public/assets/tailadmin/`.
|
||||
- `public/assets/uploads/*` — folder upload (dengan `.gitkeep`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Checklist migrasi bertahap
|
||||
|
||||
Gunakan urutan ini; centang setelah tiap fase stabil di staging.
|
||||
|
||||
### Fase A — Lingkungan & data
|
||||
|
||||
1. [ ] Samakan versi PHP target dengan CI4; backup DB produksi.
|
||||
2. [ ] Dokumentasikan skema tabel yang dipakai `Json.php` (ER ringkas atau export struktur saja).
|
||||
3. [ ] `.env` CI4: koneksi DB terpisah / read-only untuk eksperimen awal (opsional).
|
||||
|
||||
### Fase B — API mobile (prioritas kompatibilitas klien)
|
||||
|
||||
4. [x] Implementasi `login` + `login_w_token` (+ endpoint lain) di CI4 — **kode siap**; verifikasi di staging wajib.
|
||||
5. [ ] Pindahkan validasi pegawai-by-token ke **filter** / **service** tunggal (`MobileAuthService`).
|
||||
6. [ ] `profil` — ekstrak query ke model; tes parity JSON dengan CI3.
|
||||
|
||||
### Fase C — Presensi & file
|
||||
|
||||
7. [ ] `presensi_today` + insert baris harian — transaction + tes race condition.
|
||||
8. [ ] `save_masuk` / `save_pulang` / `save_istirahat` — satu domain **PresensiService**; perbaiki logika toleransi jika sudah diverifikasi user bisnis.
|
||||
9. [ ] Unified handler upload (cuti / aktivitas / absen / profil) + storage path CI4 (folder `public/assets/uploads` sudah disiapkan).
|
||||
|
||||
### Fase D — Fitur sekunder mobile
|
||||
|
||||
10. [ ] Cuti: `cuti`, `save_cuti`, `batalkan_cuti` + relasi dokumen.
|
||||
11. [ ] `berita`, `lembur`, `libur`, `aktifitas`, `daftar_today`.
|
||||
12. [ ] `save_password` — bcrypt + policy password.
|
||||
|
||||
### Fase E — Admin & HMVC
|
||||
|
||||
13. [ ] Inventarisasi modul `admin` per controller; rencanakan modul CI4 (Shield, custom admin, atau SPA terpisah).
|
||||
14. [ ] Ganti PHPExcel di laporan; uji cetak/ekspor.
|
||||
15. [ ] Matikan rute CI3 untuk endpoint yang sudah dialihkan; proxy bertahap atau cutover DNS.
|
||||
|
||||
### Fase F — hardening
|
||||
|
||||
16. [ ] CORS ketat, HTTPS, rate limit login, audit log presensi.
|
||||
17. [ ] Hapus dependensi yang tidak terpakai; tes beban ringan pada endpoint paling sering dipanggil.
|
||||
|
||||
---
|
||||
|
||||
*Dibuat sebagai artefak persiapan migrasi; sumber CI3 tidak dimodifikasi.*
|
||||
42
docs/migration/README.md
Normal file
42
docs/migration/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Dokumentasi migrasi CI3 → CI4
|
||||
|
||||
**Sumber (read-only):** `bij.mwp.co.id`
|
||||
**Target:** `bij.mwp.co.id-ci4`
|
||||
|
||||
## Indeks
|
||||
|
||||
| Dokumen | Isi |
|
||||
|---------|-----|
|
||||
| [controllers.md](controllers.md) | Inventaris controller CI3 |
|
||||
| [models.md](models.md) | Model eksplisit + catatan query di `Json.php` |
|
||||
| [modules.md](modules.md) | HMVC (admin, api, adminlte) |
|
||||
| [routes.md](routes.md) | Routing CI3 vs CI4 |
|
||||
| [auth.md](auth.md) | Ion Auth (web) vs token mobile |
|
||||
| [risks.md](risks.md) | Risiko teknis & mitigasi |
|
||||
| [json_api_map.md](json_api_map.md) | Pemetaan lengkap API mobile |
|
||||
| [ROADMAP.md](ROADMAP.md) | Fase eksekusi & dependensi |
|
||||
| [parity-checklist.md](parity-checklist.md) | Uji parity CI3 ↔ CI4 per endpoint |
|
||||
| [parity-report.md](parity-report.md) | Hasil analisis parity, staging, readiness |
|
||||
| [LAPORAN-MIGRASI-CI3-KE-CI4.md](LAPORAN-MIGRASI-CI3-KE-CI4.md) | Laporan gabungan awal |
|
||||
| [audit-json-controller.md](audit-json-controller.md) | Audit method `Json.php` |
|
||||
|
||||
## Validasi staging (perintah)
|
||||
|
||||
```text
|
||||
php spark api:staging-validate
|
||||
php spark api:staging-validate --with-uploads
|
||||
```
|
||||
|
||||
Laporan JSON: `writable/staging/last-validation.json`.
|
||||
|
||||
## Ringkasan implementasi CI4 (saat ini)
|
||||
|
||||
- API mobile: `App\Services\Mobile\MobileJsonService` + `App\Controllers\Api\MobileJsonController`.
|
||||
- Rute: `POST /api/mobile/*` dan alias **`POST /json/*`** (kompatibilitas path CI3).
|
||||
- Admin UI dasar: `GET /admin` + layout di `app/Views/layouts/*`, aset TailAdmin di `public/assets/tailadmin/`.
|
||||
- Upload mobile: `public/assets/uploads/{dokcuti,aktifitas,absen,pengguna}`.
|
||||
|
||||
## Asumsi engineering
|
||||
|
||||
- Charset API mengikuti `LegacyUtf8Encoder` (setara `utf8ize` legacy untuk string ISO-8859-1).
|
||||
- `save_istirahat`: jika `mulai` dan `selesai` keduanya kosong, CI4 **tidak** menjalankan `UPDATE` (menghindari error); legacy CI3 sebenarnya rawan *undefined variable* — perilaku aman di CI4.
|
||||
40
docs/migration/ROADMAP.md
Normal file
40
docs/migration/ROADMAP.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Roadmap migrasi (eksekusi)
|
||||
|
||||
## Fase 1 — API inti (`Json.php`) ✅ (kerangka + logika port)
|
||||
|
||||
- [x] Audit method & tabel
|
||||
- [x] `MobileJsonService` + `MobileJsonController`
|
||||
- [x] Rute `api/mobile` + alias `json`
|
||||
- [x] Upload path di `public/assets/uploads/...`
|
||||
- [ ] Uji parity di staging dengan DB salinan
|
||||
- [ ] Sinkronisasi file upload lama dari server CI3 (jika perlu)
|
||||
|
||||
## Fase 2 — Auth & hardening
|
||||
|
||||
- [ ] Rate limit `login`
|
||||
- [ ] Rencana upgrade password (dual column / flag migrasi)
|
||||
- [ ] CORS origin spesifik per lingkungan
|
||||
- [ ] Logging audit presensi
|
||||
|
||||
## Fase 3 — Admin rebuild
|
||||
|
||||
- [ ] Pilih stack auth admin (Shield / custom)
|
||||
- [ ] Port modul `admin` per domain: Pegawai, Presensi, Laporan, …
|
||||
- [ ] Ganti PHPExcel → PhpSpreadsheet
|
||||
- [ ] Hapus / kurangi ketergantungan Grocery CRud bertahap
|
||||
|
||||
## Fase 4 — Cleanup & optimasi
|
||||
|
||||
- [ ] Pecah `MobileJsonService` menjadi service + repository/model
|
||||
- [ ] Indeks DB untuk query ramai (`presensi`, `cuti`, …)
|
||||
- [ ] Matikan CI3 endpoint per endpoint setelah cutover
|
||||
- [ ] Build TailAdmin CSS produksi (ganti CDN jika diperlukan)
|
||||
|
||||
## Dependensi
|
||||
|
||||
- DB schema sama antara CI3 dan CI4 selama transisi.
|
||||
- `app.baseURL` dan `.env` database harus benar di CI4.
|
||||
|
||||
## Risiko & blocker
|
||||
|
||||
Lihat [risks.md](risks.md).
|
||||
180
docs/migration/admin-pages-map.md
Normal file
180
docs/migration/admin-pages-map.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Peta halaman admin CI3 → CI4
|
||||
|
||||
Dokumen ini menjadikan **CodeIgniter 3** (`bij.mwp.co.id`, modul `admin`) sebagai sumber kebenaran fitur dan alur menu. **CI4** (`bij.mwp.co.id-ci4`) adalah implementasi baru dengan UI TailAdmin (shell + komponen utility Tailwind via CDN, ikon & logo lokal di `public/assets/tailadmin/`).
|
||||
|
||||
**Sumber menu & otorisasi CI3**
|
||||
|
||||
- `application/modules/admin/config/ci_bootstrap.php` — array `menu`, `page_auth`, `useful_links`.
|
||||
- `application/modules/admin/views/_partials/sidemenu.php` — render menu; cek `page_auth` per URL induk/anak (URL kosong pada induk = semua grup).
|
||||
|
||||
**Konvensi URL CI3:** relatif ke basis modul admin, umumnya `{baseURL}admin/{path}`. Contoh: `presensi/riwayat` → `.../admin/presensi/riwayat`.
|
||||
|
||||
---
|
||||
|
||||
## Ringkasan `page_auth` (Ion Auth)
|
||||
|
||||
Hanya path berikut yang punya pembatasan eksplisit di `ci_bootstrap.php`; path lain mengikuti aturan sidemenu (kosong = semua grup yang login).
|
||||
|
||||
| Path CI3 | Grup |
|
||||
|----------|------|
|
||||
| `panel` | webmaster |
|
||||
| `panel/admin_user` | webmaster |
|
||||
| `panel/admin_user_create` | webmaster |
|
||||
| `laporan` | webmaster, hrd |
|
||||
| `pegawai` | webmaster, hrd |
|
||||
| `util` | webmaster |
|
||||
|
||||
**Useful links (APK):** role `webmaster`, `penyelenggara`, `operator_cabang`, `operator_ranting`, `operator_sekolah`, `admin_soal`, `operator_soal` — di CI4 dipetakan ke fitur `apk_link` di `Config\AdminAccess`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Dashboard (Beranda)
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran (efektif) |
|
||||
|---------|------------|--------|--------|------------------|
|
||||
| `admin` atau `admin/home` | `Home` | `index` | Dashboard statistik beranda | Semua login (tidak di `page_auth`) |
|
||||
|
||||
**CI4:** `GET /admin` → `App\Controllers\Admin\Dashboard::index` (setara beranda + API).
|
||||
|
||||
---
|
||||
|
||||
## 2. Presensi
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran |
|
||||
|---------|------------|--------|--------|-------|
|
||||
| `admin/presensi` | `Presensi` | `index` | Redirect ke riwayat | Semua |
|
||||
| `admin/presensi/riwayat` | `Presensi` | `riwayat` | Data presensi (Grocery CRUD + filter tanggal) | Semua |
|
||||
| `admin/presensi/lapangan` | `Presensi` | `lapangan` | Tugas luar / lapangan | Semua |
|
||||
| `admin/presensi/lembur` | `Presensi` | `lembur` | Jadwal lembur | Semua |
|
||||
| `admin/presensi/jadwal` | `Presensi` | `jadwal` | Management jadwal | Semua |
|
||||
| `admin/presensi/libur` | `Presensi` | `libur` | Hari libur | Semua |
|
||||
| `admin/presensi/aktifitas` | `Presensi` | `aktifitas` | Rekaman aktivitas harian | Semua |
|
||||
|
||||
**CI4:** `GET /admin/presensi`, `GET /admin/presensi/detail/{id}` — **Data Presensi**; `GET /admin/presensi/lapangan|lembur|jadwal|libur|aktivitas` — submenu alat presensi (API `presensi/dilapangan`, dll.).
|
||||
|
||||
---
|
||||
|
||||
## 3. Perusahaan
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran |
|
||||
|---------|------------|--------|--------|-------|
|
||||
| `admin/perusahaan` | `Perusahaan` | `index` | Redirect ke data | Semua |
|
||||
| `admin/perusahaan/data` | `Perusahaan` | `data` | Lokasi kerja | Semua |
|
||||
| `admin/perusahaan/unit_kerja` | `Perusahaan` | `unit_kerja` | Unit kerja | Semua |
|
||||
| `admin/perusahaan/golongan` | `Perusahaan` | `golongan` | Golongan | Semua |
|
||||
| `admin/perusahaan/jabatan` | `Perusahaan` | `jabatan` | Jabatan | Semua |
|
||||
| `admin/perusahaan/berita` | `Perusahaan` | `berita` | Berita / pengumuman | Semua |
|
||||
|
||||
**CI4:** `GET /admin/perusahaan/kantor|unit_kerja|golongan|jabatan|berita` — CRUD master (API `company/*`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Pegawai
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran |
|
||||
|---------|------------|--------|--------|-------|
|
||||
| `admin/pegawai` | `Pegawai` | `index` | Redirect ke `data` | webmaster, hrd |
|
||||
| `admin/pegawai/data` | `Pegawai` | `data` | Daftar / kelola pegawai | webmaster, hrd |
|
||||
| `admin/pegawai/reset_pass/{id}` | `Pegawai` | `reset_pass` | Reset password | webmaster, hrd |
|
||||
| `admin/pegawai/cuti` | `Pegawai` | `cuti` | Data cuti (aliran lama) | webmaster, hrd |
|
||||
| `admin/pegawai/dokumen_cuti/...` | `Pegawai` | `dokumen_cuti` | Dokumen cuti | webmaster, hrd |
|
||||
| `admin/pegawai/get_dokumen_cuti/...` | `Pegawai` | `get_dokumen_cuti` | Ambil file dokumen | webmaster, hrd |
|
||||
| `admin/pegawai/approve_cuti/...` | `Pegawai` | `approve_cuti` | Setujui cuti | webmaster, hrd |
|
||||
| `admin/pegawai/reject_cuti/...` | `Pegawai` | `reject_cuti` | Tolak cuti | webmaster, hrd |
|
||||
|
||||
**CI4:** `GET /admin/pegawai`, create/edit/store/update/delete/reset — modul cuti terpisah di `/admin/cuti` (setara fungsi cuti admin).
|
||||
|
||||
---
|
||||
|
||||
## 5. Cuti (alur baru CI4)
|
||||
|
||||
Di CI3 cuti utama dari menu Pegawai → **Data Cuti** (`pegawai/cuti`). Di CI4 dipisah menjadi modul `admin/cuti` dengan API terpusat.
|
||||
|
||||
---
|
||||
|
||||
## 6. Laporan
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran |
|
||||
|---------|------------|--------|--------|-------|
|
||||
| `admin/laporan/fstatistik` | `Laporan` | `fstatistik` | Statistik presensi | webmaster, hrd |
|
||||
| `admin/laporan/cetak_statistik` | `Laporan` | `cetak_statistik` | Cetak statistik | webmaster, hrd |
|
||||
| `admin/laporan/jatuhtempo` | `Laporan` | `jatuhtempo` | Piutang jatuh tempo | webmaster, hrd |
|
||||
| `admin/laporan/cetak_piutang_jatuh_tempo` | `Laporan` | `cetak_piutang_jatuh_tempo` | Cetak | webmaster, hrd |
|
||||
| `admin/laporan/penjualan` | `Laporan` | `penjualan` | Penjualan | webmaster, hrd |
|
||||
| `admin/laporan/cetak_penjualan` | `Laporan` | `cetak_penjualan` | Cetak | webmaster, hrd |
|
||||
| `admin/laporan/laba` | `Laporan` | `laba` | Laba | webmaster, hrd |
|
||||
| `admin/laporan/cetak_laba` | `Laporan` | `cetak_laba` | Cetak | webmaster, hrd |
|
||||
| `admin/laporan/fcuti` | `Laporan` | `fcuti` | Laporan cuti pegawai | webmaster, hrd |
|
||||
| `admin/laporan/cetak_cuti` | `Laporan` | `cetak_cuti` | Cetak cuti | webmaster, hrd |
|
||||
|
||||
**CI4:** `GET /admin/laporan` — ringkasan agregat; `GET /admin/laporan/cuti` — tabel cuti rentang (setara `fcuti`, cetak via browser). **Keuangan / cetak spreadsheet** CI3 tidak di-port ke modul ini.
|
||||
|
||||
---
|
||||
|
||||
## 7. Panel (Akses pengguna + akun)
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran |
|
||||
|---------|------------|--------|--------|-------|
|
||||
| `admin/panel/admin_user` | `Panel` | `admin_user` | Daftar pengguna Ion | webmaster |
|
||||
| `admin/panel/admin_user_create` | `Panel` | `admin_user_create` | Tambah pengguna | webmaster |
|
||||
| `admin/panel/admin_user_group` | `Panel` | `admin_user_group` | Grup pengguna | webmaster |
|
||||
| `admin/panel/admin_user_reset_password/{id}` | `Panel` | `admin_user_reset_password` | Reset password admin | webmaster |
|
||||
| `admin/panel/account` | `Panel` | `account` | Profil akun | Login |
|
||||
| `admin/panel/account_update_info` | `Panel` | `account_update_info` | Update info | Login |
|
||||
| `admin/panel/account_change_password` | `Panel` | `account_change_password` | Ganti password | Login |
|
||||
| `admin/panel/logout` | `Panel` | `logout` | Keluar | Login |
|
||||
|
||||
**CI4:** `GET /admin/logout` + login terpadu; `GET/POST /admin/panel/users` (+ create, reset password). **Grup-only screen** (`admin_user_group`) belum ada halaman dedikasi (grup dipilih saat buat user).
|
||||
|
||||
---
|
||||
|
||||
## 8. Utilitas
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan | Peran |
|
||||
|---------|------------|--------|--------|-------|
|
||||
| `admin/util/list_db` | `Util` | `list_db` | Daftar file backup DB | webmaster |
|
||||
| `admin/util/backup_db` | `Util` | `backup_db` | Backup | webmaster |
|
||||
| `admin/util/restore_db` | `Util` | `restore_db` | Restore | webmaster |
|
||||
| `admin/util/remove_db` | `Util` | `remove_db` | Hapus file backup | webmaster |
|
||||
| `admin/util/download_db/{file}` | `Util` | `download_db` | Unduh backup | webmaster |
|
||||
|
||||
**CI4:** `GET/POST /admin/util/backup` — daftar file, jalankan backup, unduh, hapus (tanpa restore otomatis).
|
||||
|
||||
---
|
||||
|
||||
## 9. Errors
|
||||
|
||||
| URL CI3 | Controller | Method | Tujuan |
|
||||
|---------|------------|--------|--------|
|
||||
| (routing error) | `Errors` | `page_missing` | Halaman tidak ditemukan |
|
||||
|
||||
**CI4:** penanganan error bawaan CI4.
|
||||
|
||||
---
|
||||
|
||||
# Pemetaan CI3 → CI4
|
||||
|
||||
| Halaman / alur CI3 | Status CI4 | Catatan |
|
||||
|----------------------|------------|---------|
|
||||
| `Home::index` | `/admin` — `Admin\Dashboard` | Parity fungsi inti via API |
|
||||
| `Presensi::riwayat` | `/admin/presensi`, detail | Filter tanggal + q |
|
||||
| `Presensi::lapangan/lembur/libur/jadwal/aktifitas` | `/admin/presensi/...` | CRUD lewat API |
|
||||
| `Perusahaan::*` | `/admin/perusahaan/...` | CRUD lewat API |
|
||||
| `Pegawai::data` | `/admin/pegawai` | + create/edit |
|
||||
| `Pegawai::cuti` + approve/reject | `/admin/cuti` | Alur dipisah modul |
|
||||
| `Laporan::fstatistik` + cetak | `/admin/laporan` | Ringkasan; cetak spreadsheet tidak |
|
||||
| `Laporan::fcuti` | `/admin/laporan/cuti` | Tabel + cetak browser |
|
||||
| `Laporan::keuangan*` | — | Tidak di-port |
|
||||
| `Panel::admin_user*` | `/admin/panel/users` | + create / reset password |
|
||||
| `Panel::admin_user_group` | — | Grup lewat dropdown create user |
|
||||
| `Panel::account*` | — | Bisa memakai profil API; belum halaman dedikasi |
|
||||
| `Panel::logout` | `/admin/logout` | |
|
||||
| `Util::list/backup/download/remove_db` | `/admin/util/backup` | Tanpa restore |
|
||||
|
||||
---
|
||||
|
||||
## Referensi file CI3
|
||||
|
||||
- Controller: `application/modules/admin/controllers/*.php`
|
||||
- Menu & auth: `application/modules/admin/config/ci_bootstrap.php`
|
||||
- Sidemenu view: `application/modules/admin/views/_partials/sidemenu.php`
|
||||
200
docs/migration/admin-rebuild.md
Normal file
200
docs/migration/admin-rebuild.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# 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.php` — `hasRole()`, `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/login` — `Auth::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-Token` — **struktur 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|libur|jadwal|aktivitas` | Alat presensi CI3 |
|
||||
| GET/POST | `/api/admin/panel/users|groups|…` | Panel pengguna Ion |
|
||||
| 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/lapangan` … `aktivitas` | Master alat presensi (dilapangan, lembur, libur, jadwal, aktivitas) |
|
||||
| `/admin/perusahaan/kantor` … `berita` | 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`.
|
||||
54
docs/migration/audit-json-controller.md
Normal file
54
docs/migration/audit-json-controller.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Audit detail: `Json.php` (CI3)
|
||||
|
||||
**Path sumber:** `bij.mwp.co.id/application/controllers/Json.php`
|
||||
**Base class:** `MY_Controller` → `MX_Controller` (HMVC; **Json tidak memakai Ion Auth untuk request API**).
|
||||
|
||||
## Ringkasan eksekutif
|
||||
|
||||
- **22 method publik** (termasuk `index`).
|
||||
- Hampir semua endpoint: **POST** `token` (+ field lain), balasan **JSON**, header **`Access-Control-Allow-Origin: *`**.
|
||||
- **Tidak ada layer Model**; semua interaksi DB di controller.
|
||||
|
||||
## Tabel per method
|
||||
|
||||
| Method | Login/token | Pegawai | Mobile | DB langsung | Catatan refactor |
|
||||
|--------|-------------|---------|--------|-------------|------------------|
|
||||
| `index` | — | — | — | Tidak | Hanya pesan tolak |
|
||||
| `login_w_token` | Ya | Ya | Ya | Ya | Update `last_login`; unset field sensitif |
|
||||
| `login` | Ya | Ya | Ya | Ya | MD5 password; token random di DB |
|
||||
| `profil` | token | Ya | Ya | Ya | Banyak join logika jadwal/libur/cuti; kompleks |
|
||||
| `save_cuti` | token | Ya | Ya | Ya | Base64 file + insert `cuti` + `cuti_dokumen` |
|
||||
| `batalkan_cuti` | token | Ya | Ya | Ya | Update status |
|
||||
| `save_aktifitas` | token | Ya | Ya | Ya | Upload + `aktifitas_harian` |
|
||||
| `save_masuk` | token | Ya | Ya | Ya | Jadwal dinamis kolom `{N}_in`; update `presensi` |
|
||||
| `save_pulang` | token | Ya | Ya | Ya | Verifikasi waktu pulang; cek field toleransi |
|
||||
| `save_istirahat` | token | Ya | Ya | Ya | Update partial `presensi`; variabel `$ist` bisa tak terdefinisi jika kedua POST kosong |
|
||||
| `presensi_today` | token | Ya | Ya | Ya | Insert default `presensi` jika belum ada; `serialize($jadwal)` |
|
||||
| `presensi` | token | Ya | Ya | Ya | Riwayat 20 hari |
|
||||
| `daftar_today` | token | Ya | Ya | Ya | Join `pegawai`/`jabatan`/`presensi`; tanggal di string SQL |
|
||||
| `berita` | token | — | Ya | Ya | Pagination `dari`/`jumlah` |
|
||||
| `cuti` | token | Ya | Ya | Ya | N+1 query dokumen per baris cuti |
|
||||
| `lembur` | token | Ya | Ya | Ya | — |
|
||||
| `libur` | token | — | Ya | Ya | Semua libur (tidak difilter pegawai) |
|
||||
| `aktifitas` | token | Ya | Ya | Ya | — |
|
||||
| `save_pp` | token | Ya | Ya | Ya | Hapus foto lama `unlink`; update `pegawai.photo` |
|
||||
| `save_password` | token | Ya | Ya | Ya | Bandingkan MD5 password lama |
|
||||
|
||||
## Query / DB — pola yang dipakai
|
||||
|
||||
- `pegawai`: hampir selalu filter `token` atau kredensial login.
|
||||
- Lookup terkait: `kantor`, `jabatan`, `unit_kerja`, `lembur`, `dilapangan`, `libur`, `cuti`, `jadwal`, `presensi`, `berita`, `cuti_dokumen`, `aktifitas_harian`.
|
||||
|
||||
## Private helpers
|
||||
|
||||
- `generateRandomString` — untuk suffix token setelah login.
|
||||
- `utf8ize` — rekursif array/string; memakai **`utf8_encode`** pada string (perlu pengganti di PHP 8+).
|
||||
|
||||
## Prioritas implementasi di CI4 (usulan)
|
||||
|
||||
1. `login`, `login_w_token`, `profil`
|
||||
2. `presensi_today`, `save_masuk`, `save_pulang`, `save_istirahat`
|
||||
3. `save_cuti`, `cuti`, `batalkan_cuti`
|
||||
4. Sisanya menurut frekuensi pemakaian aplikasi mobile.
|
||||
|
||||
Implementasi CI4: `app/Controllers/Api/MobileJsonController.php` + `app/Services/Mobile/MobileJsonService.php` (lihat juga [json_api_map.md](json_api_map.md)).
|
||||
29
docs/migration/auth.md
Normal file
29
docs/migration/auth.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Autentikasi & otorisasi
|
||||
|
||||
## Web (admin / site)
|
||||
|
||||
- **Ion Auth** (`application/third_party/ion_auth`), di-autoload (`application/config/autoload.php`).
|
||||
- Login form: `Site::login` + `Site::login_auth` memanggil `$this->ion_auth->login()`.
|
||||
- Pembatasan halaman: `MY_Controller` membaca `page_auth` dari config modul (`ci_bootstrap.php`) dan `ion_auth->in_group()`.
|
||||
|
||||
### CI4 (rencana)
|
||||
|
||||
- Opsi: **CodeIgniter Shield**, **Myth\Auth**, atau port minimal Ion Auth (berat).
|
||||
- Admin layout saat ini **belum** memakai filter login — sengaja untuk foundation UI.
|
||||
|
||||
## API mobile (`Json.php` / CI4 `MobileJsonService`)
|
||||
|
||||
- **Login:** `username` + `password` → hash **MD5** di kolom `pegawai.password` (kompatibilitas dipertahankan).
|
||||
- **Token:** string disimpan di kolom `pegawai.token`; diperbarui saat login; divalidasi per-request via POST `token`.
|
||||
- **Bukan** JWT dari modul `api` (`Jwt_client.php`) — dua jalur autentikasi terpisah.
|
||||
|
||||
### Peningkatan masa depan (tanpa memutus mobile sekarang)
|
||||
|
||||
- Password: `password_hash` + kolom migrasi bertahap atau dual-verify.
|
||||
- Token: JWT stateless + refresh, atau token hash di DB.
|
||||
- Rate limiting pada `login`.
|
||||
|
||||
## File terkait CI4
|
||||
|
||||
- `app/Services/Mobile/MobileJsonService.php` — `login`, `loginWToken`, `savePassword`
|
||||
- `app/Libraries/LegacyUtf8Encoder.php` — encoding respons (bukan auth)
|
||||
50
docs/migration/controllers.md
Normal file
50
docs/migration/controllers.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Controller CI3 — inventaris
|
||||
|
||||
**Total controller root (`application/controllers/`): 4**
|
||||
|
||||
| File | Peran | Ekuivalen CI4 (rencana) |
|
||||
|------|--------|-------------------------|
|
||||
| `Json.php` | API JSON mobile (presensi, cuti, profil, …) | `App\Controllers\Api\MobileJsonController` + `App\Services\Mobile\MobileJsonService` (**diimplementasi**) |
|
||||
| `Site.php` | Login web, redirect, `login_auth` (Ion Auth) | `App\Controllers\Auth\*` (TODO) + view |
|
||||
| `Cli.php` | Cron / backup DB via CLI | `app/Commands/*` (TODO) |
|
||||
| `Errors.php` | `404_override` → `page_missing` | `app/Controllers\Errors` atau exception handler CI4 (TODO) |
|
||||
|
||||
## Controller modul HMVC (`application/modules/*/controllers/`)
|
||||
|
||||
**Total: 12 file**
|
||||
|
||||
### Modul `admin` (8)
|
||||
|
||||
| Controller | Fungsi perkiraan |
|
||||
|------------|------------------|
|
||||
| `Home.php` | Dashboard admin |
|
||||
| `Pegawai.php` | Data pegawai |
|
||||
| `Presensi.php` | Presensi / riwayat |
|
||||
| `Perusahaan.php` | Master perusahaan |
|
||||
| `Laporan.php` | Laporan / cetak |
|
||||
| `Panel.php` | Admin user / akun |
|
||||
| `Util.php` | Utilitas / list DB |
|
||||
| `Errors.php` | Error modul |
|
||||
|
||||
### Modul `api` (3)
|
||||
|
||||
| Controller | Fungsi |
|
||||
|------------|--------|
|
||||
| `Home.php` | Entry API / dokumentasi ringkas |
|
||||
| `Swagger.php` | Swagger UI |
|
||||
| `Errors.php` | Error API |
|
||||
|
||||
### Modul `adminlte` (1)
|
||||
|
||||
| Controller | Fungsi |
|
||||
|------------|--------|
|
||||
| `Widget.php` | Widget UI |
|
||||
|
||||
## CI4 saat ini
|
||||
|
||||
| Area | Path |
|
||||
|------|------|
|
||||
| API mobile | `app/Controllers/Api/MobileJsonController.php` |
|
||||
| Admin shell | `app/Controllers/Admin/Dashboard.php` |
|
||||
|
||||
**Kompleksitas:** tinggi pada domain presensi + cuti + upload; admin HMVC bergantung Grocery CRUD / view legacy.
|
||||
46
docs/migration/json_api_map.md
Normal file
46
docs/migration/json_api_map.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Pemetaan API mobile (`Json.php` → CI4)
|
||||
|
||||
Semua endpoint: **POST**, header respons **`Content-Type: application/json`**, **`Access-Control-Allow-Origin: *`**.
|
||||
|
||||
**URL CI4:**
|
||||
|
||||
- `POST {baseURL}api/mobile/{method}`
|
||||
- Alias: `POST {baseURL}json/{method}` (sama dengan path CI3 `json/{method}`)
|
||||
|
||||
## Ringkasan method
|
||||
|
||||
| Method CI3 | Handler CI4 | Input POST utama | Output utama |
|
||||
|------------|---------------|-------------------|--------------|
|
||||
| `login_w_token` | `login_w_token` | `token` | `{status,pesan}` |
|
||||
| `login` | `login` | `username`, `password` | `{status,pesan,token?}` |
|
||||
| `profil` | `profil` | `token` | `{status,pesan,pegawai?}` |
|
||||
| `save_cuti` | `save_cuti` | `token`, `nama_photo`, `photo` (base64), `tanggal`, `alasan`, `tipe` | `{status,pesan}` |
|
||||
| `batalkan_cuti` | `batalkan_cuti` | `token`, `id` | `{status,pesan}` |
|
||||
| `save_aktifitas` | `save_aktifitas` | `token`, `nama_photo`, `photo`, `tanggal`, `deksripsi` | `{status,pesan}` |
|
||||
| `save_masuk` | `save_masuk` | `token`, `nama_photo`, `photo`, `lat`, `lng`, `jarak` | `{status,pesan}` |
|
||||
| `save_pulang` | `save_pulang` | sama seperti masuk | `{status,pesan}` |
|
||||
| `save_istirahat` | `save_istirahat` | `token`, `mulai`, `selesai` | `{status,pesan}` |
|
||||
| `presensi_today` | `presensi_today` | `token` | `{status,pesan,data?}` |
|
||||
| `presensi` | `presensi` | `token` | `{status,pesan,data?}` |
|
||||
| `daftar_today` | `daftar_today` | `token` | `{status,pesan,data?}` |
|
||||
| `berita` | `berita` | `token`, `dari`, `jumlah` | `{status,pesan,data?}` |
|
||||
| `cuti` | `cuti` | `token`, `dari`, `jumlah` | `{status,pesan,data?}` |
|
||||
| `lembur` | `lembur` | `token`, `dari`, `jumlah` | `{status,pesan,data?}` |
|
||||
| `libur` | `libur` | `token` | `{status,pesan,data?}` |
|
||||
| `aktifitas` | `aktifitas` | `token`, `dari`, `jumlah` | `{status,pesan,data?}` |
|
||||
| `save_pp` | `save_pp` | `token`, `nama_photo`, `photo` | `{status,pesan}` |
|
||||
| `save_password` | `save_password` | `token`, `pass_lama`, `pass_baru` | `{status,pesan}` |
|
||||
|
||||
`status`: **1** sukses, **0** gagal / tidak berubah (sesuai pola legacy).
|
||||
|
||||
## Implementasi CI4
|
||||
|
||||
- Controller: `app/Controllers/Api/MobileJsonController.php`
|
||||
- Layanan: `app/Services/Mobile/MobileJsonService.php`
|
||||
- Encoding JSON: `app/Libraries/LegacyUtf8Encoder.php`
|
||||
|
||||
## Peningkatan terjadwal (tidak mengubah kontrak sekarang)
|
||||
|
||||
- Ganti MD5 setelah mobile mendukung algoritma baru.
|
||||
- Token → JWT / hash penyimpanan.
|
||||
- Pecah service menjadi model per tabel + transaksi.
|
||||
22
docs/migration/models.md
Normal file
22
docs/migration/models.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Model CI3
|
||||
|
||||
**Total file di `application/models/`: 4**
|
||||
|
||||
| Model | Konteks |
|
||||
|-------|---------|
|
||||
| `User_model.php` | Pola CI Bootstrap / pengguna |
|
||||
| `Group_model.php` | Grup pengguna |
|
||||
| `Admin_user_model.php` | Admin user |
|
||||
| `Api_key_model.php` | Kunci API (modul REST) |
|
||||
|
||||
## Catatan penting
|
||||
|
||||
Controller **`Json.php` (mobile) tidak memakai model di atas**; seluruh akses data dilakukan lewat query builder langsung di CI3. Di CI4, logika tersebut dipindah ke **`App\Services\Mobile\MobileJsonService`** (masih monolitik; bisa dipecah ke `PegawaiModel`, `PresensiModel`, dll. pada fase berikutnya).
|
||||
|
||||
## Tabel yang disentuh API mobile (dari audit `Json.php`)
|
||||
|
||||
`pegawai`, `kantor`, `jabatan`, `unit_kerja`, `lembur`, `dilapangan`, `libur`, `cuti`, `jadwal`, `presensi`, `berita`, `cuti_dokumen`, `aktifitas_harian`.
|
||||
|
||||
## Stub CI4
|
||||
|
||||
- `app/Models/PegawaiModel.php` — kerangka; field/`$allowedFields` TODO setelah migrasi skema resmi.
|
||||
35
docs/migration/modules.md
Normal file
35
docs/migration/modules.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Modul HMVC CI3
|
||||
|
||||
HMVC memakai **MX** (`application/third_party/MX/`). `MY_Controller` extends `MX_Controller`.
|
||||
|
||||
## Modul: `admin`
|
||||
|
||||
- **Controllers:** `Home`, `Pegawai`, `Presensi`, `Perusahaan`, `Laporan`, `Panel`, `Util`, `Errors`
|
||||
- **Views:** banyak template CRUD, laporan cetak, partial layout (`_layouts`, `_partials`)
|
||||
- **Libraries modul:** `Ciqrcode.php`, `Sortable.php`
|
||||
- **Config modul:** `ci_bootstrap.php`, `grocery_crud.php`, `form_validation.php`, `image_crud.php`, `ion_auth.php`
|
||||
|
||||
**Pemetaan CI4 (fase berikut):**
|
||||
|
||||
| CI3 admin | CI4 sasaran |
|
||||
|-----------|-------------|
|
||||
| CRUD Grocery | Resource controller + model / paket CRUD modern |
|
||||
| Laporan + PHPExcel | PhpSpreadsheet + view PDF/HTML |
|
||||
| Views PHP | View CI4 bertahap atau SPA terpisah |
|
||||
|
||||
## Modul: `api`
|
||||
|
||||
- **Controllers:** `Home`, `Swagger`, `Errors`
|
||||
- **Libraries:** `Jwt_client.php` (Firebase JWT) — **terpisah** dari token kolom `pegawai` yang dipakai `Json.php` mobile.
|
||||
|
||||
**CI4:** pertahankan dokumentasi OpenAPI di `docs/`; implement JWT terpadu (opsional) setelah cutover mobile.
|
||||
|
||||
## Modul: `adminlte`
|
||||
|
||||
- **Controllers:** `Widget.php` — komponen UI.
|
||||
|
||||
**CI4:** bisa digabung ke partial view admin atau dihapus jika tidak terpakai.
|
||||
|
||||
## Third_party utama (relasi modul)
|
||||
|
||||
- `ion_auth`, `grocery_crud`, `image_crud`, `rest_server`, `MX`
|
||||
135
docs/migration/parity-checklist.md
Normal file
135
docs/migration/parity-checklist.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Checklist uji parity API mobile (CI3 `Json.php` ↔ CI4)
|
||||
|
||||
Gunakan DB & data yang sama. Bandingkan **string body JSON** (atau parse lalu diff struktur) antara:
|
||||
|
||||
- CI3: `POST .../index.php/json/{endpoint}`
|
||||
- CI4: `POST .../json/{endpoint}` atau `POST .../api/mobile/{endpoint}`
|
||||
|
||||
Aktifkan logging sementara: set **`API_PARITY_LOG=true`** di `.env`, lalu cek `writable/logs/api_parity-YYYY-MM-DD.log` (hanya diisi oleh request **HTTP** ke `MobileJsonController`, bukan oleh CLI).
|
||||
|
||||
**Otomatisasi staging:** jalankan `php spark api:staging-validate` (dan opsional `--with-uploads`) — hasil mesin di `writable/staging/last-validation.json`; ringkasan manusia di `parity-report.md`.
|
||||
|
||||
---
|
||||
|
||||
## Aturan umum verifikasi
|
||||
|
||||
- [ ] Kunci JSON sama (tidak ada field tambahan di CI4 kecuali kesalahan tak terduga).
|
||||
- [ ] Tipe: `status` integer 0/1; `pesan` string; array/objek nested sama.
|
||||
- [ ] `utf8ize` / string Latin-1: bandingkan escape `\uXXXX` jika ada karakter non-ASCII.
|
||||
- [ ] Tanpa `JSON_PRETTY_PRINT` di lingkungan development CI4 untuk string match (sudah dipaksa `json_encode(..., 0)` di controller).
|
||||
|
||||
---
|
||||
|
||||
## 1. login
|
||||
|
||||
- [ ] **Request:** `username`, `password` (POST).
|
||||
- [ ] **Gagal:** `{ "status": 0, "pesan": "Username atau Password tidak sesuai" }` (tanpa `token`).
|
||||
- [ ] **Sukses:** `status` 1, `pesan` "Selamat datang", `token` string panjang (md5(id)+15 char).
|
||||
- [ ] **DB:** kolom `token` & `last_login` ter-update.
|
||||
|
||||
## 2. login_w_token
|
||||
|
||||
- [ ] **Request:** `token`.
|
||||
- [ ] **Gagal token:** `status` 0, `pesan` "".
|
||||
- [ ] **Sukses:** `status` 1, `pesan` "" (tanpa objek pegawai di root — sama CI3).
|
||||
|
||||
## 3. profil
|
||||
|
||||
- [ ] **Request:** `token`.
|
||||
- [ ] **Gagal:** `status` 0, `pesan` "", tanpa `pegawai`.
|
||||
- [ ] **Sukses:** `pegawai` dengan nested `kantor`, `jabatan`, `unit_kerja`, `lembur`, `dilapangan` (boolean), `jadwal` (objek dengan `hari`, `masuk`, `pulang`, `istirahat`, `toleransi_masuk`, `toleransi_pulang`, `libur`, `ket_libur` jika ada).
|
||||
- [ ] **Perilaku libur perusahaan:** pada hari libur nasional/perusahaan, `ket_libur` terisi; `libur` tetap `true` seperti CI3 (tidak di-set `false` di cabang libur).
|
||||
|
||||
## 4. presensi_today
|
||||
|
||||
- [ ] **Request:** `token`.
|
||||
- [ ] **Sukses:** `data` objek; jika baru insert, `id_presensi` string bentuk `"12."` (angka + titik).
|
||||
- [ ] **Kolom null/string:** konsisten dengan baris DB yang sama di CI3.
|
||||
|
||||
## 5. presensi
|
||||
|
||||
- [ ] **Request:** `token`.
|
||||
- [ ] **Ada data:** `status` 1, `data` array (maks 20).
|
||||
- [ ] **Tanpa data:** `status` 0, tanpa kunci `data` (sama CI3).
|
||||
|
||||
## 6. save_masuk
|
||||
|
||||
- [ ] **Request:** `token`, `nama_photo`, `photo` (base64), `lat`, `lng`, `jarak`.
|
||||
- [ ] **Tanpa pegawai / tanpa jadwal:** `status` 0, `pesan` "Tidak ada jadwal kerja".
|
||||
- [ ] **Upload gagal:** `pesan` "Photo Kehadiran GAGAL upload" (dua spasi).
|
||||
- [ ] **Sukses:** file di `public/assets/uploads/absen/masuk/`, `status` 1.
|
||||
- [ ] **Catatan:** CI3 tidak mengembalikan URL file di JSON — hanya `pesan`; CI4 sama.
|
||||
|
||||
## 7. save_pulang
|
||||
|
||||
- [ ] Sama pola upload + pesan gagal/sukses.
|
||||
- [ ] **Belum waktunya pulang:** `pesan` persis: `Belum waktunya Pulang, waktu pulang anda adalah pukul {jam}. Jika anda memerlukan...` (titik setelah jam).
|
||||
|
||||
## 8. save_istirahat
|
||||
|
||||
- [ ] **Request:** `token`, `mulai`, `selesai`.
|
||||
- [ ] **Sukses normal:** `status` 1, `pesan` "berhasil disimpan".
|
||||
- [ ] **Catatan CI4:** jika `mulai` dan `selesai` keduanya kosong, CI4 **tidak** menjalankan `UPDATE` (menghindari error); CI3 PHP 7 bisa memicu perilaku tak terdefinisi — dokumentasi di `parity-report.md`.
|
||||
|
||||
## 9. save_aktifitas
|
||||
|
||||
- [ ] Folder `public/assets/uploads/aktifitas/`, pesan sukses/gagal sama.
|
||||
|
||||
## 10. save_cuti
|
||||
|
||||
- [ ] Folder `public/assets/uploads/dokcuti/`, insert `cuti` + `cuti_dokumen`.
|
||||
|
||||
## 11. batalkan_cuti
|
||||
|
||||
- [ ] **Request:** `token`, `id`.
|
||||
- [ ] **Sukses:** `pesan` berisi `Ajuan di batalkan {id} - {id_pegawai}`.
|
||||
|
||||
## 12. berita
|
||||
|
||||
- [ ] **Request:** `token`, `dari`, `jumlah` (opsional kosong → default seperti CI3).
|
||||
- [ ] **Token valid:** `status` 1 selalu, `data` array (boleh kosong).
|
||||
|
||||
## 13. cuti
|
||||
|
||||
- [ ] **Token valid:** `status` 1, `data` array; tiap item bisa punya `dokumen` array.
|
||||
- [ ] **Tanpa baris cuti:** `data` = `[]`.
|
||||
|
||||
## 14. lembur
|
||||
|
||||
- [ ] Sama seperti berita/cuti untuk pagination & `status` 1 + `data`.
|
||||
|
||||
## 15. libur
|
||||
|
||||
- [ ] **Token valid:** `status` 1, `data` seluruh tabel libur (urutan `tanggal_libur` desc).
|
||||
|
||||
## 16. aktifitas
|
||||
|
||||
- [ ] `status` 1 + `data` untuk token valid.
|
||||
|
||||
## 17. daftar_today
|
||||
|
||||
- [ ] **Request:** `token`.
|
||||
- [ ] **Ada rekan dengan presensi hari ini:** `status` 1, `data` array join pegawai/jabatan/presensi.
|
||||
- [ ] **Kosong:** `status` 0 (sama CI3).
|
||||
|
||||
## 18. save_pp
|
||||
|
||||
- [ ] Folder `public/assets/uploads/pengguna/`, hapus foto lama jika ada.
|
||||
- [ ] Pesan gagal upload: "Photo Kehadiran GAGAL upload" (teks sama CI3 meskipun konteks profil).
|
||||
|
||||
## 19. save_password
|
||||
|
||||
- [ ] **Request:** `token`, `pass_lama`, `pass_baru`.
|
||||
- [ ] **Default gagal (token salah):** `pesan` "-".
|
||||
- [ ] **Password lama salah:** pesan sesuai CI3.
|
||||
- [ ] **Sukses:** `status` 1, pesan "Password berhasil di ubah".
|
||||
|
||||
---
|
||||
|
||||
## Ringkasan
|
||||
|
||||
| Total endpoint | 19 |
|
||||
|----------------|----|
|
||||
| Verifikasi wajib | POST + JSON body + efek samping DB/file |
|
||||
|
||||
**Status readiness setelah uji manual:** centang kolom “lulus” per lingkungan sebelum cutover.
|
||||
106
docs/migration/parity-report.md
Normal file
106
docs/migration/parity-report.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Laporan parity CI3 ↔ CI4 (API `Json.php`)
|
||||
|
||||
## Status akhir (staging)
|
||||
|
||||
| Indikator | Nilai |
|
||||
|-----------|--------|
|
||||
| **Readiness** | **SAFE FOR CUTOVER (API mobile, lingkungan staging yang diuji)** |
|
||||
| **Kondisi** | DB `dodolnan_bij` lokal; `php spark api:staging-validate` **35/35 PASS** (termasuk `--with-uploads` untuk `save_pp`). |
|
||||
| **Risiko sisa** | Lihat bagian *Risiko setelah staging* — bukan blocker untuk cutover API jika item ditindaklanjuti. |
|
||||
|
||||
---
|
||||
|
||||
## Validasi staging (otomatis) — 2026-04-18
|
||||
|
||||
### Persiapan yang dilakukan
|
||||
|
||||
- **`.env`** dibuat/diisi: koneksi DB selaras `application/config/database.php` CI3, `API_PARITY_LOG=true`, `app.appTimezone=UTC`, `app.baseURL` ke `public/`.
|
||||
- **Perintah:** `php spark api:staging-validate` dan `php spark api:staging-validate --with-uploads`
|
||||
- **Artefak:** `writable/staging/last-validation.json` (hasil mesin terbaru).
|
||||
|
||||
### Ringkasan hasil
|
||||
|
||||
| Metrik | Nilai |
|
||||
|--------|--------|
|
||||
| Kasus uji dieksekusi | **35** |
|
||||
| Lulus | **35** |
|
||||
| Gagal | **0** |
|
||||
| Perbaikan kode pada sesi staging ini | **0** (tidak ada mismatch baru) |
|
||||
|
||||
### Cakupan per endpoint
|
||||
|
||||
| Area | Apa yang diuji |
|
||||
|------|----------------|
|
||||
| **DB** | `SELECT 1` |
|
||||
| **Edge invalid** | `login`, `login_w_token`, `profil`, `presensi_today`, `presensi`, `save_*`, `batalkan_cuti`, `berita`, `cuti`, `lembur`, `libur`, `aktifitas`, `daftar_today`, `save_pp`, `save_password` dengan token kosong/salah |
|
||||
| **Token valid** (ambil token pertama di tabel `pegawai`) | `login_w_token`, `profil`, `presensi_today`, `presensi`, `berita`, `cuti`, `lembur`, `libur`, `aktifitas`, `daftar_today`, `save_istirahat` (mulai & selesai kosong — perilaku CI4 terdokumentasi) |
|
||||
| **Upload** | `--with-uploads`: `save_pp` dengan GIF 1×1 base64, verifikasi file di `public/assets/uploads/pengguna/`, hapus file, revert kolom `photo` |
|
||||
| **Folder upload** | Writable: `dokcuti`, `aktifitas`, `absen/masuk`, `absen/pulang`, `pengguna` |
|
||||
|
||||
### Yang belum diuji otomatis pada run ini
|
||||
|
||||
- **`login` sukses** (username/password nyata) — hindari kredensial di repo; uji manual / env terpisah.
|
||||
- **`save_masuk` / `save_pulang` / `save_cuti` / `save_aktifitas` sukses** dengan foto base64 besar — hanya jalur invalid yang diuji otomatis.
|
||||
- **`batalkan_cuti` sukses**, **`save_password` sukses** — butuh id cuti valid / password env (`STAGING_VALIDATE_PASS` tersedia untuk cabang “password lama salah” saja).
|
||||
- **HTTP penuh** (CORS, `index.php`, reverse proxy) — pengujian CLI memanggil `MobileJsonService` langsung (setara logika controller). Untuk log `api_parity-*.log`, lakukan request HTTP ke `MobileJsonController` (logging tidak aktif di CLI).
|
||||
|
||||
### Log `api_parity-*.log`
|
||||
|
||||
File ini diisi hanya saat request **HTTP** ke `MobileJsonController` dengan `API_PARITY_LOG=true`. Jalur Spark **tidak** menulis log tersebut.
|
||||
|
||||
---
|
||||
|
||||
## Perbaikan kompatibilitas (sesi sebelumnya — baseline)
|
||||
|
||||
| Area | Masalah potensial vs CI3 | Perbaikan |
|
||||
|------|--------------------------|------------|
|
||||
| Serialisasi JSON | Formatter CI4 ≠ `json_encode` default CI3 | `MobileJsonController::respondLegacy()` memakai `json_encode(..., 0, 512)` + `setBody` |
|
||||
| `utf8ize` | Perbedaan dengan `utf8_encode` CI3 | `@utf8_encode()` untuk string |
|
||||
| `base64_decode` | Mode strict | Tanpa strict, seperti CI3 |
|
||||
| Upload | `file_put_contents` return `0` | Cek `=== false` + string kosong setelah decode |
|
||||
| `save_password` | `===` vs `==` | `==` seperti CI3 |
|
||||
|
||||
---
|
||||
|
||||
## Analisis statis (referensi)
|
||||
|
||||
| Endpoint | Catatan |
|
||||
|----------|---------|
|
||||
| login | Struktur `status` / `pesan` / `token` |
|
||||
| login_w_token | Respons sukses tanpa `token` di JSON |
|
||||
| profil | Nested + `jadwal` |
|
||||
| presensi_today | `id_presensi` bentuk `{id}.` pada insert baru |
|
||||
| presensi | Tanpa `data` jika tidak ada baris |
|
||||
| save_masuk / save_pulang | Pesan & update |
|
||||
| save_istirahat | **Deviasi:** mulai & selesai keduanya kosong → CI4 tidak `UPDATE` (CI3 rawan undefined) |
|
||||
| save_aktifitas, save_cuti, batalkan_cuti | |
|
||||
| berita, cuti, lembur, libur, aktifitas, daftar_today | |
|
||||
| save_pp, save_password | |
|
||||
|
||||
---
|
||||
|
||||
## Risiko setelah staging
|
||||
|
||||
1. **Timezone produksi:** CI3 memakai `time_reference = local`; CI4 `.env` saat ini `UTC` — samakan dengan server CI3 produksi sebelum cutover (`app.appTimezone`).
|
||||
2. **`app.baseURL`** harus benar untuk klien mobile / reverse proxy.
|
||||
3. **Charset:** `.env` memakai `utf8` / `utf8_general_ci` selaras CI3; jika DB sudah `utf8mb4`, sesuaikan dan re-uji.
|
||||
4. **Uji HTTP + log parity** ke endpoint `/json/*` atau `/api/mobile/*` sebelum matikan CI3.
|
||||
5. **Upload berat & MIME** — uji manual dengan aplikasi nyata.
|
||||
|
||||
---
|
||||
|
||||
## Kesimpulan
|
||||
|
||||
| Status | Kapan memakai |
|
||||
|--------|----------------|
|
||||
| **SAFE FOR CUTOVER (API mobile)** | Setelah staging ini: DB nyata, 35 kasus otomatis lulus, upload `save_pp` round-trip OK. Terapkan risiko #1–#4 di produksi. |
|
||||
| **NEEDS TESTING** | Jika DB / timezone / baseURL berubah atau belum ada uji HTTP dari klien mobile. |
|
||||
| **NOT READY** | Jika `api:staging-validate` gagal atau muncul mismatch baru — perbaiki, lalu perbarui laporan ini. |
|
||||
|
||||
Perintah ulang validasi:
|
||||
|
||||
```bash
|
||||
cd bij.mwp.co.id-ci4
|
||||
php spark api:staging-validate
|
||||
php spark api:staging-validate --with-uploads
|
||||
```
|
||||
25
docs/migration/risks.md
Normal file
25
docs/migration/risks.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Risiko migrasi
|
||||
|
||||
| Risiko | Dampak | Mitigasi |
|
||||
|--------|--------|----------|
|
||||
| **MD5 password** | Kompromi kredensial mudah | Rencanakan upgrade bcrypt/argon; sementara pertahankan untuk kompatibilitas mobile |
|
||||
| **Token plain di DB** | Token bocor = impersonation | Hash token di DB + bandingkan; atau JWT pendek umur |
|
||||
| **CORS `*`** | Origin jahat memanggil API jika kombinasi browser | Setelah cutover, batasi origin; tetap POST + token |
|
||||
| **Upload base64** | Beban memori / file besar / MIME palsu | Validasi ukuran, tipe, virus scan; limit body |
|
||||
| **Path upload** | Salah permission / traversal | `public/assets/uploads` + nama file random (sudah mirip legacy) |
|
||||
| **Query join `daftar_today`** | Dulu string tanggal inline | Di CI4 memakai `escape()`; tetap review indeks DB |
|
||||
| **serialize(`jadwal`) di presensi** | Kaku saat skema berubah | JSON column atau normalisasi jadwal |
|
||||
| **PHPExcel** | Usang, tidak aman | Ganti PhpSpreadsheet saat modul laporan dimigrasi |
|
||||
| **HMVC + Grocery** | Tidak ada port 1:1 CI4 | Rencanakan ulang modul admin per domain |
|
||||
| **TailAdmin source** | `css/style.css` memakai `@import "tailwindcss"` — perlu build untuk CSS penuh | Foundation admin memakai **Tailwind CDN**; aset TailAdmin (logo, FA) disalin; untuk pixel-perfect jalankan build template |
|
||||
|
||||
## Blocker potensial
|
||||
|
||||
- **Kredensial DB** harus diisi manual di `.env` CI4 (jangan commit secret).
|
||||
- **Selisih charset** DB `utf8` (CI3) vs `utf8mb4` (CI4 default) — uji karakter Indonesia.
|
||||
- **File upload** yang sudah ada di server CI3 (`assets/uploads/...`) perlu **sinkron** atau symlink jika sharing storage dengan CI4.
|
||||
|
||||
## Dependensi eksternal
|
||||
|
||||
- PHP ≥ 8.2 (CI4 appstarter).
|
||||
- MySQL/MariaDB dengan skema yang sama antara CI3 dan CI4 selama transisi.
|
||||
29
docs/migration/routes.md
Normal file
29
docs/migration/routes.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Routing CI3 vs CI4
|
||||
|
||||
## CI3 (`application/config/routes.php`)
|
||||
|
||||
- `default_controller` = `site`
|
||||
- `404_override` = `errors/page_missing`
|
||||
- Pola bahasa URL: `^(\w{2})/(.*)$` → segment berikutnya
|
||||
- Pola REST modul `api`: `api/(:any)/(:num)` → `api/$1/id/$2` (CI Bootstrap + codeigniter-restserver)
|
||||
|
||||
**`Json` controller:** tidak didefinisikan eksplisit; mengikuti routing default `controller/method` → `/json/login`, dll.
|
||||
|
||||
## CI4 (`app/Config/Routes.php`)
|
||||
|
||||
| Kebutuhan | Rute |
|
||||
|-----------|------|
|
||||
| Beranda default | `GET /` → `Home::index` |
|
||||
| Admin (foundation) | `GET /admin` → `Admin\Dashboard::index` |
|
||||
| API mobile (utama) | `POST /api/mobile/{method}` → `Api\MobileJsonController::{method}` |
|
||||
| **Alias kompatibilitas CI3** | `POST /json/{method}` → handler yang sama |
|
||||
|
||||
## Strategi cutover
|
||||
|
||||
1. Deploy CI4 di hostname/subpath terpisah; uji parity respons per endpoint.
|
||||
2. Alihkan aplikasi mobile ke base URL CI4; gunakan **`/json/*`** agar path relatif sama dengan CI3 (tanpa mengubah path di kode klien jika sebelumnya `/index.php/json/...`).
|
||||
3. Setelah stabil, opsional: standarkan ke `/api/mobile/*` dan hentikan CI3 untuk endpoint tersebut.
|
||||
|
||||
## Catatan `index.php`
|
||||
|
||||
CI3 sering memakai `index.php` di URL; CI4 `public/index.php` + rewrite. Samakan konfigurasi web server (Apache/Nginx) agar `baseURL` di `.env` sesuai.
|
||||
Reference in New Issue
Block a user