# Work Report — Paket Gabungan (perbaikan error 500 saat login)

## Kalau kamu barusan kena error 500 saat login — baca ini dulu

Penyebabnya sudah ketemu dan diperbaiki di paket ini. Ada dua hal yang terjadi
bersamaan di servermu:

1. **Sisa file lama menutupi konfigurasi baru.** Paket ZIP versi awal menaruh
   `includes/config.php` berisi contoh (`GANTI_nama_database`). Extract paket
   baru tidak menghapus file lama itu, dan aplikasi membacanya **lebih dulu**
   daripada `config.php` yang benar — jadi koneksi database selalu gagal.
2. **Halaman errornya mengirim status HTTP 500.** Di hosting cPanel, status 500
   memicu halaman error default server yang menutupi pesan penjelasan — jadi
   yang terlihat cuma "500 Internal Server Error" polos.

**Yang diperbaiki di paket ini:**

- Konfigurasi bersama di folder induk sekarang **selalu menang**; file config
  yang masih berisi contoh `GANTI_...` diabaikan otomatis.
- `install.php` mendeteksi sisa config lama dan **menyingkirkannya otomatis**
  saat kamu klik Pasang sekarang (di-rename, tidak dihapus, dan tetap aman —
  isinya tidak bisa dibaca lewat browser).
- Tidak ada lagi error 500 polos: kalau database bermasalah (config belum ada,
  password salah, tabel belum dibuat, ekstensi PHP mati), halaman login/beranda
  menampilkan **penjelasan penyebab + tombol ke install.php** — bukan layar error.
- `install.php` punya panel **Cek Sistem**: versi PHP, ekstensi (pdo_mysql,
  pdo_sqlite, gd, dst), status config, koneksi, dan status tabel tiap aplikasi.
  Apa pun masalahnya, kelihatan di situ.

**Cara memperbaiki servermu sekarang (2 menit):**

1. Extract ZIP ini di folder induk (timpa file lama)
2. Buka `https://domainanda/install.php` → panel Cek Sistem akan menunjukkan
   sisa config lama yang terdeteksi → isi data MySQL (sudah terisi otomatis
   kalau `config.php` induk ada) → klik **Pasang sekarang**
3. Login normal lagi. Selesai — lalu hapus `install.php`.

---

Satu ZIP untuk kedua aplikasi. Pemasangan lewat **satu halaman**, tanpa
mengedit file apa pun.

---

## Pasang dalam 4 langkah

### 1. Buat 1 database di cPanel

cPanel → **MySQL Databases**:

| | |
|---|---|
| Create New Database | misal `wr` |
| Add New User | misal `wruser` + password kuat |
| Add User To Database | centang **ALL PRIVILEGES** |

Cukup **satu** database untuk kedua aplikasi — masing-masing memakai awalan
tabel sendiri (`duct_` dan `plumb_`), jadi datanya tetap terpisah rapi.

cPanel menambahkan awalan nama akun, jadi nama aslinya jadi seperti
`rotoroot_wr` dan `rotoroot_wruser`. Salin persis nama itu.

### 2. Upload & extract

Extract ZIP ini di folder **induk** yang berisi `ducting/` dan `plumbing/`
(biasanya `public_html/`). Strukturnya sudah sesuai, tidak ada folder pembungkus.

### 3. Buka install.php

```
https://domainanda/install.php
```

Halaman ini akan:

1. Mendeteksi sendiri aplikasi yang ada
2. Meminta 4 isian: host, nama database, user, password
3. Membuat `config.php` otomatis
4. Membuat semua tabel untuk kedua aplikasi
5. Memindahkan data lama dari `database/app.sqlite` masing-masing aplikasi

Semuanya sekali klik. Aman dijalankan berulang — tidak ada data yang dihapus,
tidak ada yang dobel, dan foto di `uploads/` tidak disentuh sama sekali.

### 4. Cek lalu hapus install.php

Buka kedua aplikasi, pastikan Riwayat Laporan tampil normal, coba buat laporan
baru dengan banyak foto. Kalau beres, **hapus `install.php`** dari server.

---

## Yang diperbaiki: upload 100 foto selalu gagal

**Ini bukan soal sinyal.** `upload_stage.php` lama membuka session lewat
`current_user()` tapi tidak pernah menutupnya. PHP mengunci file session selama
request berjalan, jadi upload yang seharusnya paralel malah antre satu per satu
sampai kena timeout 30 detik, lalu diulang, lalu antre lagi. Dengan 100 foto,
batas 12 percobaan habis dan muncul pesan "sinyal jelek".

Dibuktikan dengan tes 6 upload paralel (masing-masing 0,5 detik):

| | Waktu |
|---|---|
| Kode lama (session dikunci) | **3,01 dtk** — benar-benar antre |
| Kode baru (session dilepas) | **1,00 dtk** — jalan bersamaan |

Ditambah lagi: dulu 1 foto = 1 request, jadi 100 foto = 100+ request. cPanel
membatasi jumlah proses PHP bersamaan, sehingga sebagian request ditolak server.

**Perbaikannya:**

1. `session_write_close()` dipanggil sebelum foto diproses → upload paralel
   benar-benar jalan bersamaan
2. Upload **batch**: 6 foto per request, 3 request paralel. 100 foto jadi
   **17 request**, bukan 100
3. Gagal parsial: kalau 1 foto dalam batch gagal, hanya foto itu yang diulang
4. Batch mengecil otomatis kalau server menolak ukuran POST
5. `set_time_limit(300)` di `store.php` / `update.php` supaya simpan ratusan
   foto tidak terputus di tengah

---

## Catatan penting

**`config.php` tidak ikut di ZIP.** Kalau nanti extract ulang paket ini,
kredensial MySQL kamu aman — tidak akan tertimpa.

**Password teknisi.** Pada pemindahan **pertama**, password dari data lama
dipakai (bukan password default `Jakarta@2026`). Kalau installer dijalankan
ulang setelah teknisi mengganti password, password baru mereka **tidak**
ter-reset.

**ID lama dipertahankan**, jadi semua link, QR, dan PDF lama tetap valid.

**Simpan `database/app.sqlite`** tiap aplikasi sebagai cadangan setelah beres.

---

## Menyetel kecepatan upload

Di `<aplikasi>/assets/js/app.js`, bagian atas blok Uploader:

```js
var UPLOAD_BATCH        = 6;      // foto per request
var UPLOAD_PARALLEL_REQ = 3;      // request paralel maksimum
```

- Sinyal lapangan sering putus → turunkan `UPLOAD_BATCH` ke `3`
- Hosting kuat & sinyal bagus → naikkan ke `8`–`10`
- Jangan naikkan `UPLOAD_PARALLEL_REQ` di atas 4; di sinyal lemah malah rebutan
  pipa dan jadi lebih lambat

Ukuran & kualitas kompresi foto (menentukan besar file = lama upload):

```js
var MAX_DIM = 1280;   // sisi terpanjang
var QUALITY = 0.65;   // kualitas JPEG
```

---

## Isi paket

```
install.php                      <- BARU, installer gabungan
PANDUAN.md
ducting/  &  plumbing/
  ├─ includes/schema.php         <- BARU, skema + pemindah data bersama
  ├─ includes/db.php             <- MySQL + awalan tabel + config bersama
  ├─ includes/functions.php      <- cache staging_dir, SQL portabel
  ├─ includes/ai.php             <- ikut skema MySQL bersama
  ├─ init_db.php                 <- DDL MySQL (opsional, install.php sudah)
  ├─ migrate_to_mysql.php        <- pemindah per-aplikasi (opsional)
  ├─ upload_stage.php            <- batch + session_write_close
  ├─ store.php, update.php       <- set_time_limit, kolom `datetime`
  ├─ index.php, login.php, history.php
  └─ assets/js/app.js            <- Uploader batch + retry parsial + adaptif
```

`uploads/`, `vendor/`, `database/`, CSS, dan gambar **tidak ikut** — jadi foto
dan data di server aman.

---

## Hasil pengujian

Diuji nyata di MariaDB 10.11 + PHP 8.3, satu database bersama, kedua aplikasi:

- Installer: 1 form → 14 tabel berawalan, kedua aplikasi termigrasi
  (30 laporan + 360 foto masing-masing), dijalankan 2× tidak menggandakan
- Isolasi: ducting dan plumbing tidak saling melihat data
- Upload 100 foto (1280px): **100/100 berhasil, 0 gagal**, 17 request
- Simpan laporan 100 foto: 100 baris DB, 100 file fisik, 0 hilang, 0 rusak,
  pengelompokan 10 titik benar
- Edit (tambah foto ke laporan lama), hapus (cascade DB + file fisik) — bersih
- Export PDF 100 foto: 22 halaman, 102 gambar, 5,2 detik
- QR publik (site & laporan) tetap jalan
- Password: migrasi pertama pakai data lama; installer diulang → password baru
  teknisi tetap berlaku
- Semua halaman kedua aplikasi: HTTP 200, tanpa error SQL
