# Status Proyek

## Status Rilis

**Siap Produksi — Implementasi dan Testing Manual Selesai**

## Status Saat Ini

Fase 2, mikro-fase 3.1–3.4, mikro-fase 4.1–4.4, mikro-fase 5.1–5.3, dan mikro-fase 6.1–6.3 telah diimplementasikan:

- autentikasi empat role tanpa role Admin;
- session aman dengan timeout aktivitas 120 menit;
- middleware auth, guest, dan role;
- CSRF untuk login, profil, perubahan kata sandi, dan logout;
- dashboard dasar PEGAWAI, TU, PIMPINAN, dan TEKNISI;
- profil pengguna dan perubahan kata sandi;
- logout POST dengan konfirmasi;
- tabel `users` dan empat akun pengembangan lokal.
- tabel inti `assets`, `tickets`, `ticket_files`, dan `ticket_logs`;
- model dasar aset, tiket, file tiket, dan log tiket;
- konstanta status, prioritas, dan tipe file;
- enam aset representatif untuk pengembangan.
- dashboard Pegawai memakai agregasi tiket milik pengguna login;
- daftar tiket Pegawai dengan pencarian, filter status/prioritas, dan pagination;
- tampilan tabel desktop, kartu mobile, serta empty state.
- formulir pengajuan tiket Pegawai dengan pilihan aset dan validasi backend;
- upload minimal satu foto JPG/PNG/WEBP ke penyimpanan privat;
- nomor tiket unik `TK-YYYY-XXXX`, status awal `DIAJUKAN`, dan audit log;
- notifikasi otomatis kepada seluruh akun TU aktif dalam transaksi pengajuan;
- route file privat dengan pemeriksaan role dan kepemilikan tiket.
- detail tiket milik Pegawai dengan informasi laporan, aset, status, prioritas, dan SLA;
- galeri foto kerusakan privat dengan modal sederhana;
- timeline status kronologis dari `ticket_logs` tanpa menampilkan catatan internal role lain;
- panel tindakan hanya-baca untuk tiket berstatus `DIAJUKAN`.
- dashboard TU berbasis jumlah tiket tindak lanjut nyata;
- antrean TU untuk status `DIAJUKAN`, `REVISI_DIAJUKAN`, dan `TERVERIFIKASI` dengan pencarian, filter, serta pagination;
- detail pemeriksaan TU berisi identitas Pegawai, aset, kerusakan, foto privat, dan timeline;
- panel hasil pemeriksaan pada detail TU;
- keputusan TU untuk meminta revisi dengan alasan wajib atau menyatakan tiket valid;
- tabel riwayat `verifications` dengan hasil `REVISI` atau `VALID`;
- transaksi pemeriksaan yang mencakup status, verification, ticket log, dan notifikasi Pegawai;
- status guard dengan row lock untuk mencegah keputusan ganda.
- tombol revisi pada detail Pegawai hanya untuk tiket miliknya yang berstatus `REVISI`;
- formulir revisi berisi data tiket saat ini dan catatan revisi TU terbaru;
- pengajuan ulang mempertahankan seluruh foto lama dan menerima foto kerusakan tambahan opsional;
- transaksi pengajuan ulang memperbarui tiket menjadi `REVISI_DIAJUKAN`, menambah audit log, dan memberi notifikasi kepada seluruh TU aktif;
- pemeriksaan kepemilikan, CSRF, row lock, dan status guard melindungi alur revisi Pegawai.
- antrean TU mencakup tiket `TERVERIFIKASI` yang siap diajukan kepada Pimpinan;
- halaman pengajuan menampilkan ringkasan tiket, foto kerusakan, dan hasil verifikasi valid terbaru;
- catatan pengajuan wajib disimpan pada `ticket_logs.note` sebagai konteks audit;
- transaksi pengajuan mengubah status menjadi `MENUNGGU_PERSETUJUAN` dan memberi notifikasi kepada seluruh Pimpinan aktif;
- dashboard Pimpinan mulai menampilkan jumlah tiket yang menunggu keputusan tanpa menyediakan tindakan persetujuan.
- dashboard Pimpinan menampilkan statistik nyata dan lima tiket prioritas teratas;
- antrean Pimpinan untuk status `MENUNGGU_PERSETUJUAN` memiliki pencarian, filter prioritas/unit/periode, dan pagination;
- detail persetujuan menampilkan tiket, aset, Pegawai, foto privat, verifikasi TU, catatan pengajuan, dan timeline;
- policy Pimpinan membatasi detail serta foto hanya pada tiket yang masih menunggu persetujuan;
- panel keputusan tersedia sebagai placeholder nonaktif tanpa perubahan status.
- tabel `approvals` menyimpan satu keputusan `SETUJU` atau `TOLAK` per tiket;
- Pimpinan dapat menyetujui dengan catatan opsional atau menolak dengan alasan wajib;
- transaksi keputusan mencakup approval, perubahan status, ticket log, dan notifikasi TU serta Pegawai;
- row lock, status guard, CSRF, dan unique constraint mencegah keputusan ganda;
- halaman keputusan menjadi baca-saja setelah diputus dan hanya dapat dilihat kembali oleh Pimpinan yang memutuskan.
- detail Pegawai dan TU menampilkan hasil, catatan, Pimpinan pemutus, serta waktu keputusan;
- TU memiliki antrean khusus tiket `DISETUJUI` yang menunggu SLA dan penugasan;
- dashboard TU dan Pimpinan menampilkan agregasi keputusan nyata;
- tiket `DITOLAK` ditampilkan sebagai hasil final hanya-baca;
- tujuan detail per role telah disiapkan untuk integrasi pusat notifikasi.
- TU dapat menetapkan satu kali target SLA masa depan pada tiket `DISETUJUI`;
- SLA disimpan pada `tickets.sla_due_at` tanpa mengubah status tiket;
- penetapan SLA dicatat pada `ticket_logs` dan dinotifikasikan kepada Pegawai;
- antrean tiket disetujui membedakan tiket menunggu SLA dan tiket menunggu penugasan.
- tabel `assignments` menyimpan satu Teknisi penanggung jawab per tiket;
- TU dapat memilih akun Teknisi aktif pada tiket `DISETUJUI` yang sudah memiliki SLA;
- transaksi penugasan membuat assignment, mengubah status menjadi `DITUGASKAN`, mencatat audit, dan mengirim notifikasi;
- detail TU menampilkan catatan penugasan; Pegawai melihat identitas Teknisi dan waktu penugasan.
- TU memiliki halaman pemantauan dengan filter status, Teknisi, prioritas, dan kondisi SLA;
- kondisi SLA dan sisa waktu dihitung secara virtual tanpa mengubah status proses;
- dashboard TU menampilkan jumlah tiket mendekati tenggat dan terlambat dari data nyata;
- detail TU menampilkan kondisi SLA serta sisa atau keterlambatan waktu.
- pusat notifikasi tersedia untuk seluruh role dengan badge, dropdown, pagination, dan penanda baca;
- command CLI memproses pengingat SLA mendekati tenggat dan keterlambatan secara idempoten;
- pengingat SLA dikirim kepada TU dan Teknisi terkait, sementara Pimpinan pemutus ikut menerima peringatan keterlambatan;
- tiket selesai diabaikan dan proses pengingat tidak mengubah status tiket.
- empat dashboard role memakai statistik dan daftar prioritas dari database tanpa angka dummy;
- seluruh kartu statistik menjadi tautan menuju daftar atau modul yang relevan;
- dashboard TU mencakup pemeriksaan, menunggu keputusan, menunggu SLA, mendekati tenggat, dan terlambat;
- dashboard Pimpinan mencakup antrean keputusan, keputusan pribadinya, dan penyelesaian tiket yang disetujui;
- dashboard Pegawai tetap dibatasi `reported_by`, sedangkan dashboard Teknisi tetap dibatasi `technician_id`.
- TU dan Pimpinan memiliki laporan operasional dengan filter periode, status, aset, kategori isu, unit, Teknisi, dan kondisi SLA;
- laporan merangkum jumlah tiket, kepatuhan SLA, tiket tanpa SLA, dan total biaya tindakan;
- ekspor CSV memakai filter identik, metadata pembuat, pemrosesan per-batch, dan mitigasi formula injection.
- TU memiliki daftar pencarian aset baca-saja dan riwayat seluruh tiket per aset;
- TU serta Pimpinan dapat melihat audit trail lengkap per tiket dengan filter periode, pelaku, dan status tujuan;
- audit menampilkan pelaku, role, unit, status sebelum/sesudah, waktu hingga detik, dan catatan tanpa route perubahan atau penghapusan;
- tautan aset pada laporan membuka riwayat aset sesuai role, sedangkan Pegawai tetap terbatas pada timeline tiket miliknya.
- seluruh route mutasi telah diaudit tetap memakai POST dan CSRF, sementara route GET bersifat baca-saja;
- sesi terautentikasi divalidasi ulang terhadap akun aktif, username, dan role resmi pada database;
- ID sesi serta token CSRF dirotasi setelah login dan perubahan kata sandi;
- respons memiliki CSP, permission policy, anti-framing, no-store, serta HSTS saat HTTPS;
- logger meredaksi key dan pola data sensitif sebelum menulis pesan maupun context;
- baseline `database/database.sql` telah disinkronkan agar instalasi baru juga membuat `work_logs`;
- placeholder navigasi role tidak valid telah dihapus tanpa mengubah modul bisnis.
- panduan penggunaan lengkap untuk Pegawai, TU, Pimpinan, dan Teknisi tersedia;
- deployment Apache/PHP/MySQL, `.env` production, HTTPS, permission storage, cron SLA, backup, dan recovery telah didokumentasikan;
- data awal serta provisioning akun produksi didokumentasikan tanpa username/password nyata;
- matriks skenario black-box, lima alur UAT, formulir penerimaan, dan checklist penutupan tersedia;
- checklist screenshot implementasi, database aman, pengujian, dan bukti Bab IV tersedia.

## Pemeliharaan Berikutnya

Implementasi roadmap telah selesai dan testing manual telah dinyatakan lulus oleh pengguna. Perubahan berikutnya masuk dalam pemeliharaan aplikasi atau pengembangan kebutuhan baru.

## Aturan Pembaruan

Setelah agent menyelesaikan fase atau bagian penting, perbarui dokumen ini dengan:

- tanggal;
- model/agent yang digunakan;
- file yang dibuat;
- keputusan teknis;
- fitur selesai;
- masalah tersisa;
- fase berikutnya.

## Log Perubahan

### 2 Agustus 2026

- starter project dibuat;
- dokumentasi konteks ditambahkan;
- roadmap fase ditambahkan;
- prompt Fase 1 disiapkan.

### 2 Agustus 2026 — Implementasi Fase 1

**Model/agent:** Cline (AI coding agent)

**File yang dibuat:**

- `app/Config/App.php` — konfigurasi aplikasi;
- `app/Config/Database.php` — konfigurasi database;
- `app/Core/App.php` — aplikasi utama;
- `app/Core/Database.php` — koneksi PDO singleton;
- `app/Core/Request.php` — abstraksi request;
- `app/Core/Response.php` — abstraksi response;
- `app/Core/Router.php` — router GET/POST;
- `app/Core/View.php` — render view dengan layout;
- `app/Exceptions/Handler.php` — penanganan error global;
- `app/Helpers/helpers.php` — fungsi bantu;
- `app/Middleware/Middleware.php` — base middleware;
- `app/Models/Model.php` — base model;
- `app/Services/Logger.php` — logging;
- `app/Controllers/Controller.php` — base controller;
- `app/Controllers/HomeController.php` — halaman utama;
- `app/Controllers/SystemController.php` — status database;
- `app/Views/layouts/main.php` — layout Bootstrap 5;
- `app/Views/home/index.php` — halaman utama;
- `app/Views/system/database.php` — status database;
- `app/Views/errors/404.php` — halaman 404;
- `app/Views/errors/500.php` — halaman 500;
- `bootstrap/app.php` — bootstrap aplikasi;
- `config/app.php` — konfigurasi aplikasi;
- `config/routes.php` — daftar route;
- `public/index.php` — front controller;
- `public/assets/css/app.css` — CSS aplikasi;
- `public/assets/js/app.js` — JavaScript aplikasi;
- `README.md` — dokumentasi instalasi.

**Keputusan teknis:**

- koneksi PDO menggunakan singleton selama request;
- PDO memakai `ERRMODE_EXCEPTION`, `FETCH_ASSOC`, dan `EMULATE_PREPARES=false`;
- router mendukung base path subfolder;
- error production tidak menampilkan detail internal;
- log disimpan di `storage/logs/app.log`;
- semua output view di-escape.

**Fitur selesai:**

- halaman utama;
- halaman status database;
- halaman 404 dan 500;
- logging.

**Masalah tersisa:**

- belum ada fitur bisnis (sesuai batasan Fase 1).

**Fase berikutnya:**

- Fase 2 — Autentikasi dan Role.

### 2 Agustus 2026 — Review dan Hardening Fase 1

- file `.env` dan `vendor/` dikeluarkan dari paket distribusi;
- proteksi akses langsung direktori internal ditambahkan;
- router base path diperbaiki;
- error handler, logger, response, dan view diperkuat;
- APP_URL disesuaikan dengan folder `bkkbn_eticketing`;
- syntax dan route dasar diverifikasi;
- proyek dinyatakan siap memasuki Fase 2.

### 2 Agustus 2026 — Pembaruan Antarmuka Fase 1

- layout utama diubah menjadi dashboard responsif dengan sidebar dan topbar;
- palet hijau, putih, dan abu-abu muda ditetapkan sebagai identitas visual proyek;
- halaman dashboard, status database, 404, dan 500 diperbarui;
- navigasi mobile dan sidebar drawer ditambahkan;
- dokumen `docs/09-UI-DESIGN-SYSTEM.md` ditambahkan;
- gambar referensi tema disimpan di `docs/references/dashboard-theme-reference.png`;
- agent berikutnya wajib mempertahankan sistem desain ini.

### 2 Agustus 2026 — Implementasi Fase 2

**Model/agent:** Codex (GPT-5)

**File yang dibuat:**

- `app/Domain/Role.php`;
- `app/Models/User.php`;
- `app/Services/AuthService.php`;
- `app/Services/SessionManager.php`;
- `app/Middleware/AuthMiddleware.php`;
- `app/Middleware/GuestMiddleware.php`;
- `app/Middleware/RoleMiddleware.php`;
- `app/Controllers/AuthController.php`;
- `app/Controllers/DashboardController.php`;
- `app/Controllers/ProfileController.php`;
- `app/Views/layouts/auth.php`;
- `app/Views/auth/login.php`;
- `app/Views/dashboard/index.php`;
- `app/Views/profile/index.php`;
- `app/Views/profile/change-password.php`;
- `app/Views/errors/403.php`;
- `database/migrations/002_create_users_table.sql`;
- `database/seeders/seed_development_users.php`.

**File yang diubah:**

- `.env` (konfigurasi lokal, tidak untuk version control);
- `.env.example`;
- `bootstrap/app.php`;
- `config/app.php`;
- `config/routes.php`;
- `app/Core/Request.php`;
- `app/Core/Response.php`;
- `app/Core/Router.php`;
- `app/Controllers/Controller.php`;
- `app/Controllers/HomeController.php`;
- `app/Controllers/SystemController.php`;
- `app/Helpers/helpers.php`;
- `app/Views/layouts/main.php`;
- `database/database.sql`;
- `public/assets/css/app.css`;
- `public/assets/js/app.js`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

### 4 Agustus 2026 — Panduan Singkat Pengguna untuk Klien

**Status:** Selesai dan siap didistribusikan.

**File yang dibuat:**

- `docs/PANDUAN-SINGKAT-PENGGUNA.docx`.

**File yang diubah:**

- `docs/22-MANIFEST.md`;
- `docs/06-STATUS-PROJECT.md`.

**Isi dokumen:**

- cara login dan ketentuan keamanan akun;
- alur singkat tiket dari Pegawai hingga Teknisi;
- langkah tegas untuk role Pegawai, TU, Pimpinan, dan Teknisi;
- cara menggunakan notifikasi serta memahami status akhir;
- penanganan singkat kendala login, sesi, upload foto, dan hak akses.

**Keputusan penyajian:**

- menggunakan bahasa nonteknis, ringkas, dan berorientasi tindakan;
- tidak mencantumkan alamat, credential, data demo, maupun istilah fase pengembangan;
- dokumen memakai format A4 dan gaya visual hijau yang selaras dengan aplikasi;
- struktur paket DOCX dan seluruh XML penyusunnya telah divalidasi.

**Keputusan teknis:**

- middleware didefinisikan langsung pada route dan tetap diperiksa di backend;
- role dipusatkan pada konstanta `Role` dan tidak menambahkan role Admin;
- session hanya menyimpan identitas minimum, tidak menyimpan hash kata sandi;
- session ID diregenerasi setelah login dan aktivitas kedaluwarsa mengikuti `SESSION_LIFETIME`;
- seeder membaca password dari `DEV_SEED_PASSWORD`, hanya berjalan pada environment lokal, dan membuat hash dengan `PASSWORD_DEFAULT`;
- route status database lama dipertahankan dan dibatasi untuk role TU;
- fitur bisnis hanya ditampilkan sebagai menu nonaktif/placeholder.

**Fitur selesai:**

- login dan redirect otomatis empat role;
- penolakan akun nonaktif dan kredensial tidak valid dengan pesan umum;
- session timeout, logout POST, dan konfirmasi logout;
- middleware auth, guest, dan role serta halaman 403;
- dashboard dasar per role;
- lihat/ubah profil sendiri;
- perubahan kata sandi dengan verifikasi kata sandi lama;
- CSRF pada seluruh form penting;
- navigasi responsif sesuai role;
- tabel `users` dan empat akun demo diterapkan pada database lokal.

**Pemeriksaan:**

- 42 file PHP lulus validasi sintaks;
- definisi route dan kontrol keamanan diinspeksi;
- migration berhasil diterapkan pada MariaDB lokal;
- empat akun pengembangan berhasil dibuat dan jumlahnya diverifikasi;
- test suite otomatis tidak dijalankan sesuai batasan Fase 2.

**Masalah tersisa:**

- tidak ada masalah implementasi Fase 2 yang diketahui;
- akun demo dan password awal tidak boleh digunakan pada production.

**Fase berikutnya:**

- Fase 3 — Master Data, hanya setelah instruksi eksplisit.

### 2 Agustus 2026 — Mikro-Fase 3.1 Fondasi Data Aset dan Tiket

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Models/Asset.php`;
- `app/Models/Ticket.php`;
- `app/Models/TicketFile.php`;
- `app/Models/TicketLog.php`;
- `app/Services/TicketStatus.php`;
- `app/Services/TicketPriority.php`;
- `app/Services/TicketFileType.php`;
- `database/migrations/003_create_asset_ticket_foundation.sql`;
- `database/seeders/seed_development_assets.php`.

**File yang diubah:**

- `database/database.sql`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tabel `assets` dengan kode aset unik serta data nama, kategori, lokasi, dan kondisi;
- tabel `tickets` sebagai pusat relasi ke `users` dan `assets`;
- tabel `ticket_files` untuk metadata lampiran privat;
- tabel `ticket_logs` untuk riwayat perubahan status;
- enam foreign key dengan kebijakan `RESTRICT` agar riwayat tidak terhapus secara tidak sengaja;
- indeks inti untuk kode/nomor, pelapor, aset, status, prioritas, SLA, file, dan log;
- enam aset pengembangan disiapkan melalui seeder idempotent.

**Penambahan teknis yang didokumentasikan:**

- `assets.created_at` dan `assets.updated_at`;
- `tickets.created_at` dan `tickets.updated_at`;
- `ticket_files.mime_type` dan `ticket_files.file_size` untuk validasi upload pada mikro-fase mendatang;
- `ticket_no` nullable dan unique agar nomor baru diisi ketika tiket resmi dibuat;
- CHECK constraint menjaga nilai status, prioritas, dan tipe file tetap konsisten.

**Keputusan teknis:**

- status mengikuti `docs/18-DATABASE-CONSISTENCY-RULES.md`: `DIAJUKAN` hingga `SELESAI`, bukan status Inggris pada PRD lama;
- prioritas ditetapkan sebagai `RENDAH`, `SEDANG`, `TINGGI`, dan `MENDESAK`;
- tipe file dibatasi pada `BUKTI_KERUSAKAN`, `BUKTI_SELESAI`, dan `NOTA`;
- model menyediakan prepared query dasar untuk aset, daftar/detail tiket milik Pegawai, file, dan timeline;
- operasi insert model disiapkan untuk digunakan service transaksi pada mikro-fase mendatang, tetapi belum ada alur pengajuan;
- tidak ada tabel `units`, `ticket_categories`, atau role tambahan.

**Pemeriksaan seperlunya:**

- file PHP baru lulus pemeriksaan sintaks;
- empat tabel tersedia pada MariaDB lokal;
- enam foreign key dan seluruh sembilan indeks minimum terverifikasi;
- enam aset pengembangan tersedia;
- query model dasar pada kondisi tiket kosong berjalan tanpa error;
- tidak ada rangkaian testing otomatis yang dibuat atau dijalankan.

**Route baru:**

- tidak ada.

**Ringkasan handoff:**

- migration `003_create_asset_ticket_foundation.sql` sudah diterapkan dan tercatat pada tabel `migrations` lokal;
- database saat ini belum memiliki data tiket, file tiket, atau log tiket;
- dashboard dan navigasi tetap seperti Fase 2;
- mikro-fase berikutnya boleh memakai `Ticket::countOwned()`, `Ticket::paginateOwned()`, dan `Ticket::findOwnedWithAsset()` untuk data Pegawai;
- jangan membuat pengajuan, upload, atau detail UI sebelum prompt mikro-fase terkait dijalankan.

**Yang sengaja belum dikerjakan:**

- dashboard dan daftar tiket berbasis data;
- formulir pengajuan tiket;
- upload foto;
- route bisnis;
- pemeriksaan TU, persetujuan, SLA, notifikasi, dan laporan.

**Mikro-fase berikutnya:**

- 3.2 — Dashboard dan Daftar Tiket Pegawai, hanya setelah instruksi eksplisit.

### 2 Agustus 2026 — Mikro-Fase 3.2 Dashboard dan Daftar Tiket Pegawai

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/EmployeeTicketController.php`;
- `app/Services/EmployeeTicketService.php`;
- `app/Views/dashboard/pegawai.php`;
- `app/Views/tickets/employee/index.php`.

**File yang diubah:**

- `app/Controllers/DashboardController.php`;
- `app/Models/Ticket.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada tabel, kolom, migration, atau data awal baru;
- query memanfaatkan indeks `tickets.reported_by`, `tickets.status`, dan `tickets.priority` dari mikro-fase 3.1.

**Route baru dan hak akses:**

- `GET /pegawai/tiket` — hanya role `PEGAWAI`, dilindungi `AuthMiddleware` dan `RoleMiddleware`;
- `GET /pegawai/dashboard` tetap hanya role `PEGAWAI`, kini menggunakan data database.

**Keputusan teknis:**

- seluruh query dashboard dan daftar selalu memiliki kondisi `reported_by = session user_id`;
- statistik dashboard dihitung dengan satu query agregasi;
- daftar memakai 10 item per halaman dan membatasi page maksimum 100000;
- parameter search dibatasi 100 karakter, sedangkan status dan prioritas harus cocok dengan konstanta;
- filter invalid diabaikan dan page invalid kembali ke halaman pertama;
- SLA kosong ditampilkan sebagai `Belum ditetapkan`;
- tombol `Buat Tiket` ditampilkan nonaktif dengan label `Segera`, tanpa route/form pengajuan;
- view Pegawai dipisahkan dari dashboard placeholder role lain agar mikro-fase mereka tidak dikerjakan lebih awal.

**Pemeriksaan terbatas:**

- file PHP yang dibuat/diubah lulus pemeriksaan sintaks;
- route dan pemasangan middleware diinspeksi statis;
- kondisi ownership `reported_by` diinspeksi pada seluruh query terkait;
- tidak ada test suite, browser automation, request otomatis, atau testing acceptance yang dijalankan sesuai instruksi pengguna.

**Ringkasan handoff:**

- database lokal masih belum memiliki tiket, sehingga UI normalnya menampilkan angka nol dan empty state;
- `EmployeeTicketService` menjadi batas query/presentasi data dashboard serta daftar Pegawai;
- `Ticket::dashboardStatsOwned()`, `countOwned()`, dan `paginateOwned()` wajib mempertahankan scope `reported_by`;
- route detail tiket belum ada dan harus menunggu mikro-fase 3.4;
- route/form pengajuan dan upload harus menunggu mikro-fase 3.3.

**Yang sengaja belum dikerjakan:**

- formulir dan penyimpanan tiket;
- upload foto kerusakan;
- nomor tiket otomatis;
- detail tiket dan timeline;
- notifikasi bisnis, verifikasi TU, persetujuan, SLA, dan pekerjaan Teknisi.

**Mikro-fase berikutnya:**

- 3.3 — Pengajuan Tiket dan Foto Kerusakan, hanya setelah instruksi eksplisit.

### 2 Agustus 2026 — Mikro-Fase 3.3 Pengajuan Tiket dan Foto Kerusakan

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/TicketFileController.php`;
- `app/Exceptions/ValidationException.php`;
- `app/Models/Notification.php`;
- `app/Services/FileStorageService.php`;
- `app/Services/NotificationService.php`;
- `app/Services/TicketNumberService.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/TicketSubmissionService.php`;
- `app/Views/tickets/employee/create.php`;
- `database/migrations/004_create_notifications_table.sql`.

**File yang diubah:**

- `.env` (konfigurasi lokal, tidak untuk version control);
- `.env.example`;
- `app/Controllers/EmployeeTicketController.php`;
- `app/Core/Request.php`;
- `app/Core/Response.php`;
- `app/Core/Router.php`;
- `app/Models/Ticket.php`;
- `app/Models/TicketFile.php`;
- `app/Models/User.php`;
- `app/Views/dashboard/pegawai.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/employee/index.php`;
- `config/app.php`;
- `config/routes.php`;
- `database/database.sql`;
- `public/assets/css/app.css`;
- `public/assets/js/app.js`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- migration `004_create_notifications_table.sql` membuat tabel `notifications` dan sudah diterapkan serta tercatat pada database lokal;
- tabel menyimpan penerima, relasi tiket, tipe/pesan notifikasi, status baca, dan waktu baca;
- indeks ditambahkan untuk `user_id`, `ticket_id`, dan antrean notifikasi pengguna yang belum dibaca;
- foreign key ke `users` dan `tickets` memakai kebijakan `RESTRICT`;
- tidak ada data awal atau tiket contoh yang ditambahkan.

**Route baru dan hak akses:**

- `GET /pegawai/tiket/buat` — hanya role `PEGAWAI`;
- `POST /pegawai/tiket` — hanya role `PEGAWAI` dan wajib CSRF;
- `GET /files/ticket/{file_id}` — hanya role `PEGAWAI` pemilik tiket atau role `TU`;
- router sederhana diperluas untuk parameter segmen `{file_id}` tanpa mengubah pola MVC.

**Keputusan teknis:**

- nomor tiket dibentuk setelah insert menggunakan primary key: `TK-{tahun}-{ticket_id minimal 4 digit}`, sehingga bebas collision dan tetap berada dalam transaksi;
- tiket, metadata file, log awal, dan notifikasi seluruh TU aktif dibuat dalam satu transaksi PDO;
- kegagalan database, notifikasi, atau pemindahan file memicu rollback; file yang sempat dipindahkan dibersihkan;
- foto divalidasi berdasarkan error upload, ukuran, ekstensi, MIME `finfo`, dan struktur gambar sebelum disimpan;
- nama fisik file memakai 16 byte acak dan disimpan di `storage/uploads/tickets/{tahun}/{bulan}`; nama asli hanya menjadi metadata;
- batas default adalah 5 MB per file dan 5 file, dapat diatur lewat environment;
- akses foto tidak memakai URL publik langsung dan respons memakai `no-store` serta `nosniff`;
- setelah berhasil, pengguna diarahkan kembali ke daftar tiket dengan flash message. Redirect ke detail belum dipasang karena halaman/route detail adalah ruang lingkup eksplisit mikro-fase 3.4;
- preview foto di browser hanya memakai object URL lokal dan tidak mengirim data sebelum form disubmit.

**Pemeriksaan terbatas:**

- hanya inspeksi implementasi dan validasi sintaks PHP yang dilakukan;
- tidak ada test suite, browser automation, request otomatis, atau skenario acceptance yang dijalankan sesuai instruksi pengguna.

**Ringkasan handoff:**

- pengajuan resmi menghasilkan status awal `DIAJUKAN`, satu log status kosong ke `DIAJUKAN`, foto bertipe `BUKTI_KERUSAKAN`, dan satu notifikasi per akun TU aktif;
- jika tidak ada akun TU aktif, pengajuan ditolak sebelum transaksi agar tiket tanpa penerima tidak tercipta;
- route file telah siap dipakai halaman detail mendatang, tetapi UI detail belum dibuat;
- file input harus dipilih ulang setelah validasi gagal karena browser tidak mengizinkan pengisian ulang file secara otomatis;
- aturan akses file untuk Pimpinan dan Teknisi belum dibuka karena kedua role itu belum memiliki relasi akses pada tahap ini.

**Yang sengaja belum dikerjakan:**

- halaman detail tiket dan timeline;
- edit tiket, draf, verifikasi TU, permintaan revisi, dan pengajuan ulang;
- persetujuan/penolakan Pimpinan;
- SLA, penugasan, progres Teknisi, dan bukti penyelesaian;
- pusat notifikasi dan penandaan notifikasi sudah dibaca.

**Mikro-fase berikutnya:**

- 3.4 — Detail Tiket Pegawai, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 3.4 Detail Tiket dan Timeline Pegawai

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/EmployeeTicketDetailService.php`;
- `app/Views/tickets/employee/show.php`.

**File yang diubah:**

- `app/Controllers/EmployeeTicketController.php`;
- `app/Models/Ticket.php`;
- `app/Models/TicketFile.php`;
- `app/Services/TicketPolicy.php`;
- `app/Views/dashboard/pegawai.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/employee/index.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `public/assets/js/app.js`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, maupun data awal baru;
- detail memakai tiga query terukur: tiket beserta aset, foto kerusakan, dan timeline beserta identitas pelaku;
- query selalu menggunakan prepared statement dan tidak dijalankan dari view.

**Route baru dan hak akses:**

- `GET /pegawai/tiket/{ticket_id}` — hanya role `PEGAWAI`;
- `TicketPolicy::canViewEmployeeTicket()` memastikan pengguna login adalah pelapor tiket;
- tiket yang tidak ada, ID invalid, dan tiket milik Pegawai lain semuanya menghasilkan halaman 404 untuk mengurangi enumerasi ID;
- `GET /files/ticket/{file_id}` tetap menjadi satu-satunya jalur akses foto dan tetap memeriksa izin secara terpisah.

**Keputusan teknis:**

- `EmployeeTicketDetailService` menggabungkan hasil model dan membentuk label presentasi agar controller tetap tipis dan view tidak melakukan query;
- galeri hanya memuat file bertipe `BUKTI_KERUSAKAN` pada tahap ini;
- modal foto memakai JavaScript sederhana, dapat ditutup melalui tombol, klik backdrop, atau tombol Escape;
- timeline diurutkan dari kejadian paling awal berdasarkan `changed_at` dan `ticket_log_id`;
- status, aktor, role, dan waktu tetap terlihat pada timeline, tetapi isi catatan dari role selain pelapor disembunyikan sampai tersedia penanda eksplisit catatan publik/internal;
- status `DIAJUKAN` hanya menampilkan informasi menunggu pemeriksaan TU tanpa tombol edit atau tindakan;
- pengajuan sukses kini diarahkan ke detail tiket yang baru dibuat, menyelesaikan keputusan sementara pada mikro-fase 3.3;
- daftar dan dashboard Pegawai sekarang menyediakan tautan menuju detail tiket;
- layout berubah menjadi satu kolom pada layar kecil dan mempertahankan dukungan minimum 360 piksel.

**Pemeriksaan terbatas:**

- hanya validasi sintaks PHP dan inspeksi statis route, ownership, serta batas fase yang dilakukan;
- tidak ada test suite, browser automation, request otomatis, atau skenario acceptance yang dijalankan sesuai instruksi pengguna.

**Ringkasan handoff:**

- detail Pegawai menggunakan data tiket nyata dan tidak menambahkan data contoh;
- query detail pertama mengambil tiket tanpa scope pengguna agar policy dapat memutuskan akses, tetapi data tidak pernah dirender sebelum ownership lolos;
- galeri menggunakan controller file privat, bukan path `storage` atau URL publik;
- panel revisi sengaja belum tersedia walaupun service dapat menyajikan label seluruh status;
- timeline saat ini minimal berisi log pengajuan yang dibuat mikro-fase 3.3 dan otomatis akan bertambah ketika fase proses berikutnya menulis `ticket_logs`.

**Yang sengaja belum dikerjakan:**

- tombol dan form revisi Pegawai;
- antrean/detail pemeriksaan TU serta catatan pemeriksaan;
- verifikasi, permintaan revisi, dan pengajuan ke Pimpinan;
- persetujuan, SLA entry, penugasan, progres Teknisi, dan tindakan lain di luar tampilan baca;
- penandaan catatan publik/internal pada skema database.

**Mikro-fase berikutnya:**

- 4.1 — Antrean dan Detail Pemeriksaan TU, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 4.1 Antrean dan Detail Pemeriksaan TU

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/TuTicketController.php`;
- `app/Services/TuDashboardService.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Services/VerificationQueueService.php`;
- `app/Views/dashboard/tu.php`;
- `app/Views/tickets/tu/queue.php`;
- `app/Views/tickets/tu/show.php`.

**File yang diubah:**

- `app/Controllers/DashboardController.php`;
- `app/Models/Ticket.php`;
- `app/Services/TicketPolicy.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- query antrean menggabungkan `tickets`, `assets`, dan `users` dengan prepared statement;
- query detail mengambil tiket+aset+pelapor, foto kerusakan, dan timeline melalui tiga query terukur;
- seluruh query fase ini bersifat baca-saja.

**Route baru dan hak akses:**

- `GET /tu/tiket/pemeriksaan` — hanya role `TU`;
- `GET /tu/tiket/{ticket_id}/periksa` — hanya role `TU` dan hanya untuk tiket berstatus `DIAJUKAN` atau `REVISI_DIAJUKAN`;
- `GET /tu/dashboard` tetap hanya role `TU`, kini menggunakan data antrean nyata;
- ID invalid, tiket tidak ditemukan, atau status yang tidak relevan menghasilkan halaman 404;
- file foto tetap dilayani oleh controller privat yang mengizinkan role TU.

**Keputusan teknis:**

- status antrean dipusatkan pada policy dan query: `DIAJUKAN` serta `REVISI_DIAJUKAN`;
- antrean diurutkan dari tiket paling lama agar pemeriksaan terdahulu terlihat lebih dulu;
- pencarian mencakup nomor tiket, kode/nama aset, nama/username Pegawai, dan unit;
- filter mencakup status antrean, seluruh prioritas resmi, serta periode hari ini/7/30/90 hari;
- dashboard menampilkan total antrean, tiket baru, revisi diajukan, dan prioritas mendesak;
- detail TU menampilkan catatan timeline lengkap karena TU berwenang melakukan pemeriksaan internal;
- panel Hasil Pemeriksaan hanya berisi tombol nonaktif dan informasi bahwa keputusan tersedia pada 4.2;
- seluruh endpoint baru hanya memakai GET dan tidak memiliki jalur perubahan status;
- komponen galeri/modal detail Pegawai digunakan kembali tanpa membuka path penyimpanan publik.

**Pemeriksaan terbatas:**

- file PHP yang dibuat/diubah diperiksa sintaksnya;
- route, filter status, policy TU, dan ketiadaan endpoint mutasi diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- dashboard placeholder TU telah diganti dengan dashboard operasional awal berbasis database;
- menu Antrean Pemeriksaan aktif khusus TU;
- antrean tidak akan menampilkan tiket yang sudah keluar dari status pemeriksaan awal;
- detail yang sedang terbuka akan menjadi 404 bila status tiket berubah dan tidak lagi relevan;
- service/detail ini dapat menjadi fondasi aksi pemeriksaan 4.2, tetapi belum memiliki form, transaksi, verifikasi, log baru, maupun notifikasi tahap pemeriksaan.

**Yang sengaja belum dikerjakan:**

- penyimpanan hasil verifikasi;
- permintaan revisi dan alasan revisi;
- perubahan status atau penulisan `ticket_logs` baru;
- notifikasi hasil pemeriksaan;
- pengajuan tiket valid kepada Pimpinan;
- SLA dan penugasan Teknisi.

**Mikro-fase berikutnya:**

- 4.2 — Permintaan Revisi dan Verifikasi, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 4.2 Permintaan Revisi dan Verifikasi

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Exceptions/InvalidTicketStateException.php`;
- `app/Models/Verification.php`;
- `app/Services/TicketLogService.php`;
- `app/Services/VerificationService.php`;
- `database/migrations/005_create_verifications_table.sql`.

**File yang diubah:**

- `app/Controllers/TuTicketController.php`;
- `app/Models/Ticket.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/tu/queue.php`;
- `app/Views/tickets/tu/show.php`;
- `config/routes.php`;
- `database/database.sql`;
- `public/assets/css/app.css`;
- `public/assets/js/app.js`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- migration `005_create_verifications_table.sql` membuat tabel `verifications` dan sudah diterapkan serta dicatat pada database lokal;
- kolom inti: `verification_id`, `ticket_id`, `verifier_id`, `result`, dan `note`;
- kolom teknis `verified_at` mencatat waktu setiap keputusan;
- hasil dibatasi CHECK constraint menjadi `VALID` atau `REVISI`;
- indeks tersedia untuk tiket, pemeriksa, dan pencarian riwayat tiket+hasil+waktu;
- foreign key ke `tickets` dan `users` menggunakan kebijakan `RESTRICT`;
- tidak ada record verifikasi atau tiket contoh yang dibuat saat implementasi.

**Route baru dan hak akses:**

- `POST /tu/tiket/{ticket_id}/minta-revisi` — hanya role `TU`, wajib CSRF dan alasan revisi;
- `POST /tu/tiket/{ticket_id}/verifikasi` — hanya role `TU`, wajib CSRF dan konfirmasi;
- kedua route hanya menerima status `DIAJUKAN` atau `REVISI_DIAJUKAN`;
- detail GET TU tetap dapat menampilkan tiket setelah keputusan, tetapi form tindakan hanya muncul bila status masih dapat diperiksa.

**Transisi status:**

- `DIAJUKAN` → `REVISI`;
- `DIAJUKAN` → `TERVERIFIKASI`;
- `REVISI_DIAJUKAN` → `REVISI`;
- `REVISI_DIAJUKAN` → `TERVERIFIKASI`.

**Keputusan teknis:**

- `VerificationService` menjadi satu-satunya alur keputusan pemeriksaan dan mengelola transaksi PDO;
- baris tiket dikunci dengan `SELECT ... FOR UPDATE`, lalu status diperbarui memakai kondisi status lama untuk menolak request ganda;
- setiap keputusan menambahkan record `verifications`; riwayat lama tidak diperbarui atau dihapus;
- perubahan status, record verification, ticket log, dan notifikasi Pegawai berada dalam transaksi yang sama;
- alasan revisi wajib, dibersihkan dari karakter kontrol, dan dibatasi maksimal 2000 karakter;
- hasil valid tidak otomatis diajukan kepada Pimpinan dan berhenti pada `TERVERIFIKASI`;
- notifikasi revisi hanya ditujukan kepada pelapor; notifikasi status terverifikasi juga dikirim kepada pelapor sebagai informasi;
- modal revisi mempertahankan alasan ketika validasi gagal, sedangkan verifikasi valid memakai modal konfirmasi;
- setelah keputusan, TU kembali ke detail tiket untuk melihat flash message, status, dan timeline terbaru;
- antrean/dashboard otomatis berkurang karena query hanya menghitung status pemeriksaan aktif.

**Pemeriksaan terbatas:**

- file PHP yang dibuat/diubah diperiksa sintaksnya;
- transaksi, CSRF, role middleware, row lock, status guard, serta route mutasi diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau keputusan tiket uji yang dijalankan.

**Ringkasan handoff:**

- tiket `REVISI` siap menjadi input Mikro-Fase 4.3;
- catatan revisi tersimpan pada `verifications.note`, juga tercermin pada log TU, dan dapat diambil dari record `REVISI` terbaru pada fase berikutnya;
- tiket `TERVERIFIKASI` belum masuk antrean Pimpinan karena pengajuan resmi adalah Mikro-Fase 4.4;
- aksi ulang terhadap tiket yang sudah diputus ditolak tanpa membuat verification, log, atau notifikasi tambahan;
- halaman detail TU bersifat baca-saja setelah keputusan selesai.

**Yang sengaja belum dikerjakan:**

- form dan penyimpanan revisi Pegawai;
- pengajuan ulang menjadi `REVISI_DIAJUKAN`;
- pengajuan tiket terverifikasi kepada Pimpinan;
- persetujuan/penolakan Pimpinan;
- SLA dan penugasan Teknisi.

**Mikro-fase berikutnya:**

- 4.3 — Revisi dan Pengajuan Ulang Pegawai, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 4.3 Revisi dan Pengajuan Ulang Pegawai

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/RevisionService.php`;
- `app/Services/TicketDataValidator.php`;
- `app/Views/tickets/employee/revision.php`.

**File yang diubah:**

- `app/Controllers/EmployeeTicketController.php`;
- `app/Models/Ticket.php`;
- `app/Models/Verification.php`;
- `app/Services/EmployeeTicketDetailService.php`;
- `app/Services/FileStorageService.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/TicketSubmissionService.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/employee/show.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- data revisi menggunakan tabel `tickets`, `ticket_files`, `ticket_logs`, `verifications`, dan `notifications` yang telah tersedia;
- seluruh foto kerusakan lama dan riwayat verifikasi tetap dipertahankan tanpa update atau delete.

**Route baru dan hak akses:**

- `GET /pegawai/tiket/{ticket_id}/revisi` — hanya role `PEGAWAI`, pemilik tiket, dan status `REVISI`;
- `POST /pegawai/tiket/{ticket_id}/revisi` — hanya role `PEGAWAI`, pemilik tiket, status `REVISI`, dan request dengan token CSRF valid;
- akses ke tiket milik Pegawai lain, tiket tidak ditemukan, ID invalid, atau status selain `REVISI` tidak membuka formulir revisi;
- tombol Revisi Tiket hanya ditampilkan pada detail tiket ketika syarat kepemilikan dan status terpenuhi.

**Transisi status:**

- `REVISI` → `REVISI_DIAJUKAN`;
- pengajuan ulang tidak menjalankan verifikasi TU secara otomatis dan tidak meneruskan tiket kepada Pimpinan.

**Keputusan teknis:**

- `RevisionService` mengelola satu transaksi untuk row lock, perubahan data tiket, metadata foto tambahan, perubahan status, audit log, dan notifikasi;
- update tiket memakai kondisi pemilik dan status lama agar request ganda atau perubahan status bersamaan ditolak;
- `TicketDataValidator` menampung validasi data kerusakan yang dipakai bersama oleh pengajuan awal dan revisi agar aturan keduanya konsisten;
- validasi foto tambahan menggunakan aturan format, ukuran, dan jumlah yang sama dengan pengajuan awal, tetapi unggahan baru bersifat opsional;
- tiket tetap wajib memiliki sedikitnya satu foto kerusakan dari gabungan foto lama dan foto baru;
- foto baru disimpan sebagai record tambahan `BUKTI_KERUSAKAN`; foto lama tidak ditimpa dan tidak dihapus;
- bila transaksi gagal, hanya file fisik baru dari request tersebut yang dibersihkan, sedangkan seluruh file historis tetap utuh;
- formulir dipraisi dengan data tiket saat ini serta menampilkan catatan `REVISI` terbaru dari TU;
- seluruh akun TU aktif menerima notifikasi setelah revisi berhasil diajukan ulang;
- halaman detail Pegawai menjadi baca-saja kembali setelah status berubah menjadi `REVISI_DIAJUKAN`.

**Pemeriksaan terbatas:**

- file PHP yang dibuat dan diubah diperiksa sintaksnya;
- route, middleware role, CSRF, pemeriksaan kepemilikan, transaksi, row lock, status guard, retensi foto lama, serta ketiadaan alur otomatis ke Pimpinan diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- tiket berstatus `REVISI` kini dapat dikoreksi dan diajukan ulang oleh Pegawai pelapor;
- catatan revisi TU terbaru terlihat jelas pada formulir agar Pegawai mengetahui koreksi yang diminta;
- setelah berhasil, tiket masuk kembali ke antrean TU melalui status `REVISI_DIAJUKAN`;
- data laporan terbaru tersimpan pada tiket, sedangkan foto dan riwayat sebelumnya tetap menjadi jejak audit;
- alur berhenti setelah notifikasi kepada TU dan tidak mencakup pengajuan tiket valid kepada Pimpinan.

**Yang sengaja belum dikerjakan:**

- pengajuan tiket `TERVERIFIKASI` kepada Pimpinan;
- persetujuan atau penolakan Pimpinan;
- penetapan SLA dan penugasan Teknisi;
- progres pekerjaan, bukti penyelesaian, laporan, dan penutupan tiket.

**Mikro-fase berikutnya:**

- 4.4 — Pengajuan Tiket Valid ke Pimpinan, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 4.4 Pengajuan Tiket Valid kepada Pimpinan

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/SubmissionToLeaderService.php`;
- `app/Services/LeaderDashboardService.php`;
- `app/Services/TuDashboardService.php`;
- `app/Views/tickets/tu/leader-submission.php`;
- `app/Views/dashboard/pimpinan.php`.

**File yang diubah:**

- `app/Controllers/TuTicketController.php`;
- `app/Controllers/DashboardController.php`;
- `app/Models/Ticket.php`;
- `app/Models/Verification.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Services/VerificationQueueService.php`;
- `app/Views/tickets/tu/show.php`;
- `app/Views/tickets/tu/queue.php`;
- `app/Views/dashboard/tu.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- catatan pengajuan disimpan pada `ticket_logs.note` dalam record transisi baru;
- tidak ada tabel atau record `approvals` yang dibuat karena keputusan Pimpinan belum termasuk mikro-fase ini.

**Route baru dan hak akses:**

- `GET /tu/tiket/{ticket_id}/ajukan-pimpinan` — hanya role `TU` dan status `TERVERIFIKASI`;
- `POST /tu/tiket/{ticket_id}/ajukan-pimpinan` — hanya role `TU`, status `TERVERIFIKASI`, token CSRF valid, catatan valid, dan konfirmasi pengajuan;
- ID invalid, tiket tidak ditemukan, role selain TU, atau status selain `TERVERIFIKASI` tidak dapat membuka form maupun menjalankan aksi;
- tombol pengajuan hanya muncul pada detail TU dan antrean TU ketika status memenuhi policy.

**Transisi status:**

- `TERVERIFIKASI` → `MENUNGGU_PERSETUJUAN`;
- aksi ulang ditolak oleh row lock dan status guard tanpa membuat log atau notifikasi tambahan.

**Keputusan teknis:**

- `SubmissionToLeaderService` menjadi pemilik alur transaksi pengajuan kepada Pimpinan;
- transaksi mencakup row lock tiket, guarded status update, ticket log, dan notifikasi kepada seluruh Pimpinan aktif;
- pengajuan dibatalkan bila tidak ada akun Pimpinan aktif agar tiket tidak berpindah tahap tanpa penerima;
- catatan pengajuan diwajibkan dan dibatasi maksimal 2000 karakter agar perpindahan tanggung jawab memiliki konteks audit yang jelas;
- catatan tidak memakai tabel baru dan disimpan bersama log transisi sesuai opsi yang diizinkan prompt;
- halaman pengajuan menggunakan detail, foto privat, dan hasil verifikasi `VALID` terbaru yang telah tersedia;
- antrean TU diperluas secara terukur dengan status `TERVERIFIKASI`; tiket tersebut diarahkan ke halaman pengajuan, sedangkan `DIAJUKAN` dan `REVISI_DIAJUKAN` tetap diarahkan ke pemeriksaan;
- tiket keluar dari antrean TU setelah menjadi `MENUNGGU_PERSETUJUAN`;
- dashboard Pimpinan hanya membaca jumlah status `MENUNGGU_PERSETUJUAN`; daftar lengkap dan keputusan tidak dibuat sebelum 5.1/5.2;
- Pegawai tetap tidak memiliki jalur edit setelah status meninggalkan `REVISI`.

**Pemeriksaan terbatas:**

- file PHP yang dibuat dan diubah diperiksa sintaksnya;
- route, middleware role, CSRF, policy status, transaksi, row lock, guarded update, ticket log, notifikasi Pimpinan, serta ketiadaan alur persetujuan diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- TU kini memiliki jalur yang dapat ditemukan dari antrean untuk meneruskan tiket terverifikasi;
- Pimpinan menerima notifikasi dan dashboard menghitung tiket `MENUNGGU_PERSETUJUAN`;
- catatan pengajuan dapat dibaca agent fase berikutnya dari log transisi `TERVERIFIKASI` ke `MENUNGGU_PERSETUJUAN`;
- belum ada antrean detail Pimpinan dan belum ada record keputusan;
- alur berhenti tepat setelah tiket menunggu persetujuan.

**Yang sengaja belum dikerjakan:**

- dashboard dan antrean lengkap Pimpinan;
- detail peninjauan Pimpinan;
- persetujuan atau penolakan serta tabel `approvals`;
- distribusi hasil keputusan;
- SLA dan penugasan Teknisi.

**Mikro-fase berikutnya:**

- 5.1 — Dashboard dan Antrean Pimpinan, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 5.1 Dashboard dan Antrean Pimpinan

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/LeaderTicketController.php`;
- `app/Services/ApprovalQueueService.php`;
- `app/Services/LeaderTicketDetailService.php`;
- `app/Views/tickets/leader/queue.php`;
- `app/Views/tickets/leader/show.php`.

**File yang diubah:**

- `app/Models/Ticket.php`;
- `app/Models/TicketLog.php`;
- `app/Services/LeaderDashboardService.php`;
- `app/Services/TicketPolicy.php`;
- `app/Views/dashboard/pimpinan.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- seluruh query pada mikro-fase ini bersifat baca-saja;
- tabel `approvals` belum dibuat dan tidak ada record keputusan yang disimpan.

**Route baru dan hak akses:**

- `GET /pimpinan/persetujuan` — hanya role `PIMPINAN`, menampilkan antrean status `MENUNGGU_PERSETUJUAN`;
- `GET /pimpinan/tiket/{ticket_id}/persetujuan` — hanya role `PIMPINAN` dan tiket yang masih berstatus `MENUNGGU_PERSETUJUAN`;
- `GET /pimpinan/dashboard` tetap hanya role `PIMPINAN`, kini memakai statistik dan preview antrean nyata;
- route file privat menerima role Pimpinan, tetapi policy hanya mengizinkan file milik tiket `MENUNGGU_PERSETUJUAN`;
- ID invalid, tiket tidak ditemukan, atau tiket di luar scope menghasilkan halaman 404 pada detail.

**Keputusan teknis:**

- `ApprovalQueueService` memvalidasi pencarian, prioritas, unit, periode, dan pagination sebelum membentuk parameter query;
- antrean hanya membaca status `MENUNGGU_PERSETUJUAN`, sehingga query string tidak dapat memperluas scope status;
- unit filter hanya menerima nilai yang berasal dari daftar unit Pegawai pada antrean aktif;
- waktu pengajuan kepada Pimpinan dibaca dari `tickets.updated_at`; selama status menunggu, nilai tersebut merepresentasikan waktu transisi 4.4 karena tidak ada aksi edit pada tahap ini;
- urutan antrean mendahulukan `MENDESAK`, `TINGGI`, `SEDANG`, lalu `RENDAH`, kemudian tiket terlama;
- dashboard menampilkan total menunggu, Mendesak, Tinggi, dan tiket yang diajukan hari ini serta lima tiket teratas;
- `LeaderTicketDetailService` mengambil detail tiket+aset+Pegawai, foto kerusakan, verifikasi `VALID` terbaru, log pengajuan terbaru, dan timeline melalui query terukur;
- catatan pengajuan ditarik dari transisi `TERVERIFIKASI` ke `MENUNGGU_PERSETUJUAN` dan disajikan terpisah;
- timeline ditampilkan baca-saja untuk kebutuhan peninjauan dan tidak memiliki form mutasi;
- panel Setujui/Tolak hanya placeholder tombol nonaktif untuk menandai titik integrasi 5.2;
- scope file Pimpinan sengaja dibatasi ke status menunggu dan perlu diperluas secara eksplisit pada fase riwayat keputusan setelah tabel `approvals` tersedia.

**Pemeriksaan terbatas:**

- file PHP yang dibuat dan diubah diperiksa sintaksnya;
- route GET, middleware role, scope status, filter prepared statement, policy detail/file, dan ketiadaan endpoint mutasi diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- dashboard Pimpinan tidak lagi memiliki metrik placeholder untuk antrean aktif;
- menu Antrean Persetujuan aktif khusus Pimpinan dan mendukung tampilan desktop/mobile;
- prioritas Tinggi dan Mendesak terlihat jelas serta berada di urutan atas;
- detail menyediakan seluruh konteks yang dibutuhkan form keputusan fase 5.2;
- setelah tiket keluar dari `MENUNGGU_PERSETUJUAN`, detail 5.1 dan akses foto Pimpinan akan ditolak sampai policy riwayat keputusan dibuat pada fase yang relevan.

**Yang sengaja belum dikerjakan:**

- penyimpanan keputusan setuju atau tolak;
- tabel/model `approvals`;
- alasan penolakan dan catatan keputusan;
- perubahan status menjadi `DISETUJUI` atau `DITOLAK`;
- notifikasi hasil keputusan;
- SLA dan penugasan Teknisi.

**Mikro-fase berikutnya:**

- 5.2 — Persetujuan atau Penolakan, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 5.2 Persetujuan atau Penolakan Pimpinan

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Models/Approval.php`;
- `app/Services/ApprovalService.php`;
- `database/migrations/006_create_approvals_table.sql`.

**File yang diubah:**

- `app/Controllers/LeaderTicketController.php`;
- `app/Models/TicketFile.php`;
- `app/Services/LeaderTicketDetailService.php`;
- `app/Services/TicketPolicy.php`;
- `app/Views/tickets/leader/queue.php`;
- `app/Views/tickets/leader/show.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `database/database.sql`;
- `public/assets/css/app.css`;
- `public/assets/js/app.js`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- migration `006_create_approvals_table.sql` membuat tabel `approvals` dan sudah diterapkan serta dicatat pada database lokal;
- kolom inti: `approval_id`, `ticket_id`, `approver_id`, `decision`, dan `note`;
- kolom teknis `decided_at` mencatat waktu keputusan;
- `ticket_id` memiliki unique constraint untuk menjamin satu tiket satu keputusan;
- keputusan dibatasi CHECK constraint menjadi `SETUJU` atau `TOLAK`;
- indeks tersedia untuk approver serta pencarian keputusan+waktu;
- foreign key ke `tickets` dan `users` menggunakan kebijakan `RESTRICT`;
- tidak ada record approval atau keputusan tiket contoh yang dibuat saat implementasi.

**Route baru dan hak akses:**

- `POST /pimpinan/tiket/{ticket_id}/setujui` — hanya role `PIMPINAN`, CSRF valid, dan status `MENUNGGU_PERSETUJUAN`;
- `POST /pimpinan/tiket/{ticket_id}/tolak` — hanya role `PIMPINAN`, CSRF valid, status `MENUNGGU_PERSETUJUAN`, dan alasan penolakan valid;
- kedua endpoint dilindungi kembali oleh policy backend, row lock, dan guarded status update;
- setelah keputusan, hanya Pimpinan yang tercatat sebagai `approver_id` dapat melihat riwayat detail serta foto keputusan tersebut;
- Pimpinan lain tidak dapat melihat atau mengubah keputusan yang sudah tersimpan.

**Transisi status:**

- `MENUNGGU_PERSETUJUAN` → `DISETUJUI` untuk decision `SETUJU`;
- `MENUNGGU_PERSETUJUAN` → `DITOLAK` untuk decision `TOLAK`;
- tidak ada transisi koreksi atau pembatalan keputusan pada UI.

**Keputusan teknis:**

- `ApprovalService` menjadi satu-satunya alur mutasi keputusan Pimpinan;
- transaksi mencakup row lock tiket, status guard, insert approval, ticket log, dan notifikasi;
- catatan persetujuan bersifat opsional, sedangkan alasan penolakan wajib; keduanya dibatasi maksimal 2000 karakter;
- seluruh TU aktif dan Pegawai pelapor menerima record notifikasi hasil keputusan dalam transaksi yang sama;
- keputusan ganda dicegah berlapis oleh row lock, status lama pada update, dan unique constraint `approvals.ticket_id`;
- bila insert approval, log, atau salah satu notifikasi gagal, perubahan status ikut di-rollback;
- antrean dan statistik menunggu berkurang otomatis karena query 5.1 hanya membaca `MENUNGGU_PERSETUJUAN`;
- setelah redirect sukses, Pimpinan yang memutuskan tetap dapat membuka halaman detail baca-saja yang menampilkan decision, catatan, aktor, waktu, dan timeline baru;
- akses foto privat untuk tiket `DISETUJUI`/`DITOLAK` hanya diberikan kepada `approver_id` terkait;
- tombol aktif tidak dirender setelah keputusan dan request ulang tetap ditolak backend;
- keputusan belum didistribusikan ke antrean tindak lanjut TU atau proses berikutnya karena bagian tersebut termasuk 5.3.

**Pemeriksaan terbatas:**

- file PHP yang dibuat dan diubah diperiksa sintaksnya;
- struktur migration dan pencatatan migration lokal diverifikasi secara terbatas;
- CSRF, middleware role, validasi catatan, transaksi, row lock, unique constraint, status guard, log, notifikasi, dan scope riwayat diinspeksi statis;
- tidak ada test suite, browser automation, request keputusan otomatis, atau perubahan tiket uji yang dijalankan.

**Ringkasan handoff:**

- detail Pimpinan kini menjadi titik penyimpanan keputusan final;
- record approval dapat diambil berdasarkan `ticket_id` dan memuat Pimpinan pemutus serta waktu keputusan;
- tiket `DISETUJUI` dan `DITOLAK` belum masuk daftar tindak lanjut role lain selain statusnya terlihat pada detail Pegawai yang sudah tersedia;
- notifikasi hasil sudah tercatat, tetapi pusat notifikasi dan distribusi antrean operasional tetap mengikuti fase masing-masing;
- fase berikutnya dapat memakai `approvals` dan status final keputusan tanpa mengubah keputusan lama.

**Yang sengaja belum dikerjakan:**

- koreksi, pembatalan, atau keputusan kedua;
- distribusi tiket disetujui/ditolak ke halaman tindak lanjut TU;
- halaman riwayat keputusan umum;
- SLA dan penugasan Teknisi;
- pekerjaan dan bukti penyelesaian Teknisi.

**Mikro-fase berikutnya:**

- 5.3 — Distribusi Hasil Keputusan, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 5.3 Distribusi Hasil Keputusan

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/ApprovedTicketQueueService.php`;
- `app/Views/tickets/tu/approved.php`.

**File yang diubah:**

- `app/Controllers/TuTicketController.php`;
- `app/Models/Ticket.php`;
- `app/Services/EmployeeTicketDetailService.php`;
- `app/Services/NotificationService.php`;
- `app/Services/TuDashboardService.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Views/dashboard/pimpinan.php`;
- `app/Views/dashboard/tu.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/employee/show.php`;
- `app/Views/tickets/tu/show.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- data keputusan dibaca dari tabel `approvals` yang tersedia sejak mikro-fase 5.2;
- seluruh fitur baru pada mikro-fase ini bersifat baca-saja dan tidak mengubah approval maupun status tiket.

**Route baru dan hak akses:**

- `GET /tu/tiket/disetujui` — hanya role `TU`, menampilkan tiket berstatus `DISETUJUI` dengan approval `SETUJU`;
- detail hasil keputusan tetap menggunakan route milik masing-masing role dan policy yang sudah ada;
- Pegawai hanya dapat melihat keputusan tiket miliknya; TU dapat melihat detail operasional melalui route pemeriksaan; riwayat Pimpinan tetap terbatas kepada Pimpinan pemutus.

**Keputusan teknis:**

- antrean TU mengharuskan pasangan `tickets.status = DISETUJUI` dan `approvals.decision = SETUJU`, sehingga tiket ditolak tidak dapat masuk antrean SLA;
- antrean mendukung pencarian, prioritas, unit, periode keputusan, pagination, dan urutan prioritas lalu keputusan terlama;
- detail Pegawai dan TU menampilkan hasil, nama Pimpinan, catatan/alasan, serta waktu keputusan melalui model `Approval`;
- keputusan ditolak dijelaskan sebagai final dan tidak merender tindakan edit atau pengajuan ulang;
- dashboard TU menampilkan jumlah tiket pemeriksaan, menunggu SLA, serta ditolak dan menyediakan preview tiket disetujui;
- dashboard Pimpinan menampilkan agregasi nyata menunggu, disetujui, ditolak, dan tiket Mendesak yang belum diputuskan;
- `NotificationService::ticketPathForRole()` menyiapkan pemetaan tujuan detail per role untuk pusat notifikasi tanpa menambah kolom atau UI notifikasi pada fase ini;
- label `Menunggu SLA` hanya merupakan informasi tahap berikutnya; tidak ada input SLA maupun tombol penugasan.

**Pemeriksaan terbatas:**

- file PHP yang dibuat dan diubah diperiksa sintaksnya;
- route, middleware role, pembatasan status antrean, query prepared statement, ownership Pegawai, dan ketiadaan aksi SLA/assignment diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- hasil keputusan kini terdistribusi ke detail Pegawai dan TU;
- TU memiliki antrean khusus tiket disetujui sebagai titik masuk fase penetapan SLA;
- statistik keputusan Pimpinan dan TU tidak lagi memakai placeholder;
- tiket ditolak berhenti sebagai arsip final hanya-baca;
- pemetaan link notifikasi siap dipakai saat pusat notifikasi diimplementasikan.

**Yang sengaja belum dikerjakan:**

- penetapan atau perubahan SLA;
- penugasan Teknisi;
- pekerjaan Teknisi dan bukti penyelesaian;
- pusat/daftar notifikasi dan aksi tandai dibaca;
- perubahan, pembatalan, atau keputusan kedua.

**Mikro-fase berikutnya:**

- Fase 6.1 hanya boleh dimulai setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 6.1 Penetapan SLA

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/SlaService.php`;
- `app/Views/tickets/tu/sla.php`.

**File yang diubah:**

- `app/Controllers/TuTicketController.php`;
- `app/Models/Ticket.php`;
- `app/Services/ApprovedTicketQueueService.php`;
- `app/Services/EmployeeTicketDetailService.php`;
- `app/Services/LeaderTicketDetailService.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Views/dashboard/tu.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/tu/approved.php`;
- `app/Views/tickets/tu/show.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- SLA menggunakan kolom `tickets.sla_due_at` dan indeks yang telah tersedia sejak fondasi data tiket;
- tidak ada tabel assignment yang dibuat pada mikro-fase ini.

**Route baru dan hak akses:**

- `GET /tu/tiket/{ticket_id}/sla` — hanya role `TU` dan tiket berstatus `DISETUJUI` dengan approval `SETUJU`;
- `POST /tu/tiket/{ticket_id}/sla` — hanya role `TU`, CSRF valid, konfirmasi dipilih, target valid, dan SLA belum pernah ditetapkan;
- tiket ditolak, tiket dengan status lain, dan pengguna non-TU tidak dapat mengakses form SLA.

**Keputusan teknis:**

- `SlaService` menangani validasi, transaksi, penyimpanan, audit, dan notifikasi;
- input `datetime-local` diparse secara ketat memakai zona `Asia/Jakarta` dan wajib lebih besar dari waktu server saat ini;
- SLA hanya dapat ditetapkan satu kali; perubahan berulang ditolak oleh policy, row lock, pemeriksaan nilai lama, dan update `WHERE sla_due_at IS NULL`;
- transaksi mencakup update `sla_due_at`, insert `ticket_logs`, serta notifikasi `SLA_DITETAPKAN` kepada Pegawai;
- ticket log memakai status sebelum dan sesudah `DISETUJUI` untuk mencatat perubahan informasi tanpa transisi proses;
- presenter timeline menamai log tanpa perubahan status sebagai “Informasi tiket diperbarui”;
- setelah SLA tersimpan, antrean menampilkan target dan label “Menunggu Penugasan”, tetapi status tiket tetap `DISETUJUI`;
- detail Pegawai, TU, dan Pimpinan membaca target SLA dari kolom tiket yang sama.

**Pemeriksaan terbatas:**

- file PHP terkait diperiksa sintaksnya;
- route, middleware role, CSRF, validasi waktu, transaksi, row lock, guarded update, ticket log, notifikasi, dan ketiadaan assignment diinspeksi statis;
- tidak ada test suite, browser automation, request otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- tiket `DISETUJUI` tanpa SLA menyediakan tombol “Tetapkan SLA”;
- tiket yang sudah memiliki SLA menampilkan target tersimpan dan tidak menyediakan form perubahan ulang;
- `SlaService::set()` mengembalikan status `DISETUJUI`, sehingga fase ini tidak pernah menghasilkan `DITUGASKAN`;
- tiket dengan SLA siap menjadi input mikro-fase 6.2 tanpa memerlukan perubahan skema tiket.

**Yang sengaja belum dikerjakan:**

- pemilihan dan penugasan Teknisi;
- tabel/model/record assignment;
- perubahan SLA atau alasan perubahan SLA;
- indikator keterlambatan dan reminder otomatis;
- dashboard atau tugas Teknisi.

**Mikro-fase berikutnya:**

- 6.2 — Penugasan Teknisi, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 6.2 Penugasan Teknisi

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Models/Assignment.php`;
- `app/Services/AssignmentService.php`;
- `app/Views/tickets/tu/assignment.php`;
- `database/migrations/007_create_assignments_table.sql`.

**File yang diubah:**

- `app/Controllers/TuTicketController.php`;
- `app/Models/Ticket.php`;
- `app/Services/ApprovedTicketQueueService.php`;
- `app/Services/EmployeeTicketDetailService.php`;
- `app/Services/NotificationService.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/employee/show.php`;
- `app/Views/tickets/tu/show.php`;
- `app/Views/tickets/tu/sla.php`;
- `config/routes.php`;
- `database/database.sql`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- migration `007_create_assignments_table.sql` membuat tabel `assignments` dan sudah diterapkan serta dicatat pada database lokal;
- kolom inti: `assignment_id`, `ticket_id`, `technician_id`, `assigned_by`, `assigned_note`, `assigned_at`, `started_at`, dan `completed_at`;
- unique constraint `uq_assignments_ticket_id` menjamin satu tiket hanya memiliki satu assignment;
- indeks tersedia untuk Teknisi, TU penugas, serta urutan tugas Teknisi berdasarkan waktu;
- foreign key tiket, Teknisi, dan TU penugas menggunakan `RESTRICT`;
- tidak ada record assignment atau perubahan tiket contoh yang dibuat saat implementasi.

**Route baru dan hak akses:**

- `GET /tu/tiket/{ticket_id}/penugasan` — hanya role `TU`, tiket `DISETUJUI`, SLA tersedia, dan belum memiliki assignment;
- `POST /tu/tiket/{ticket_id}/penugasan` — hanya role `TU`, CSRF valid, Teknisi aktif dengan role tepat, konfirmasi dipilih, dan kondisi tiket masih valid;
- setelah berhasil, detail TU yang sudah ada menjadi halaman hasil penugasan hanya-baca.

**Transisi status:**

- `DISETUJUI` → `DITUGASKAN` setelah assignment berhasil dibuat;
- tidak ada transisi mulai kerja, progres, atau selesai pada mikro-fase ini.

**Keputusan teknis:**

- `AssignmentService` menjadi satu-satunya alur mutasi penugasan;
- transaksi mencakup row lock tiket, validasi status dan SLA, validasi ulang akun Teknisi aktif, insert assignment, guarded status update, ticket log, serta notifikasi Teknisi dan Pegawai;
- catatan penugasan opsional dan dibatasi maksimal 2000 karakter;
- assignment ganda dicegah oleh row lock, status guard, pemeriksaan record lama, dan unique constraint database;
- antrean tiket disetujui mengarahkan tiket tanpa SLA ke penetapan SLA dan tiket dengan SLA ke form penugasan;
- setelah penugasan, tiket keluar otomatis dari antrean `DISETUJUI` karena status menjadi `DITUGASKAN`;
- detail TU menampilkan Teknisi, unit, waktu, penugas, serta catatan; detail Pegawai hanya menampilkan identitas Teknisi dan waktu penugasan;
- statistik keputusan Pimpinan menghitung tabel `approvals`, sehingga jumlah keputusan setuju tidak berkurang saat tiket berubah menjadi `DITUGASKAN`;
- policy riwayat Pimpinan tetap mengizinkan Pimpinan pemutus membaca detail/foto setelah tiket memasuki status lanjutan;
- pemetaan tujuan notifikasi Teknisi disiapkan ke `/teknisi/tugas/{assignment_id}`, tetapi route dan halaman tugas tetap menunggu fase 7.1.

**Pemeriksaan terbatas:**

- file PHP yang dibuat dan diubah diperiksa sintaksnya;
- migration lokal diverifikasi melalui keberadaan tabel dan record migration;
- middleware role, CSRF, validasi Teknisi, SLA guard, transaksi, row lock, unique constraint, status guard, audit, serta notifikasi diinspeksi statis;
- tidak ada test suite, browser automation, request penugasan otomatis, atau perubahan data uji yang dijalankan.

**Ringkasan handoff:**

- model `Assignment` menyediakan insert dan detail assignment berdasarkan tiket;
- assignment memuat Teknisi, TU penugas, catatan, SLA dari tiket, dan timestamp;
- tiket `DITUGASKAN` sudah siap menjadi sumber dashboard serta daftar tugas Teknisi pada fase 7.1;
- kolom `started_at` dan `completed_at` tersedia tetapi belum dimutasi.

**Yang sengaja belum dikerjakan:**

- reassign atau perubahan Teknisi;
- pemantauan SLA dan indikator keterlambatan;
- reminder otomatis;
- dashboard dan daftar tugas Teknisi;
- mulai pekerjaan, progres, hasil tindakan, foto selesai, dan penutupan tiket.

**Mikro-fase berikutnya:**

- 6.3 — Pemantauan SLA dan Keterlambatan, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 6.3 Pemantauan SLA dan Keterlambatan

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/TuMonitoringController.php`;
- `app/Models/SlaMonitoring.php`;
- `app/Services/SlaMonitoringService.php`;
- `app/Views/tickets/tu/monitoring.php`.

**File yang diubah:**

- `app/Services/TuDashboardService.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Views/dashboard/tu.php`;
- `app/Views/layouts/main.php`;
- `app/Views/tickets/tu/show.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- pemantauan memakai indeks `tickets.status`, `tickets.sla_due_at`, dan indeks assignment Teknisi yang sudah tersedia;
- tidak ada status `TERLAMBAT` yang disimpan ke kolom `tickets.status`.

**Route baru dan hak akses:**

- `GET /tu/pemantauan` — hanya role `TU`;
- route menerima filter tervalidasi untuk status proses, Teknisi, prioritas, kondisi SLA, dan halaman;
- Pimpinan dan Teknisi tidak memperoleh akses ke halaman pemantauan TU pada mikro-fase ini.

**Status SLA virtual:**

- `BELUM_MULAI` — SLA kosong atau pekerjaan belum dimulai dan tenggat masih lebih dari 24 jam;
- `AMAN` — pekerjaan sudah dimulai dan SLA masih lebih dari 24 jam;
- `MENDEKATI` — tiket belum selesai dan SLA tersisa maksimal 24 jam;
- `TERLAMBAT` — waktu saat ini melewati SLA dan tiket belum selesai;
- `SELESAI_TEPAT_WAKTU` — waktu selesai tidak melewati SLA;
- `SELESAI_TERLAMBAT` — waktu selesai melewati SLA atau tiket selesai tidak memiliki SLA.

**Keputusan teknis:**

- `SlaMonitoring` menangani query agregasi, filter, pagination, join assignment/Teknisi, dan urutan perhatian SLA;
- `SlaMonitoringService` memvalidasi filter, membentuk label kondisi, menghitung teks sisa waktu, dan menyajikan data dashboard/detail;
- ambang “Mendekati Tenggat” ditetapkan 24 jam sebelum `sla_due_at`;
- waktu acuan dibentuk pada PHP menggunakan zona `Asia/Jakarta` lalu dikirim satu kali ke query sebagai derived clock agar konsisten dengan aplikasi;
- urutan tabel mendahulukan terlambat, mendekati, belum mulai, aman, lalu tiket selesai;
- waktu selesai menggunakan `assignments.completed_at`; `tickets.updated_at` menjadi fallback defensif untuk record selesai lama;
- filter kondisi SLA memakai predikat langsung terhadap status, SLA, dan assignment agar indeks terkait tetap dapat digunakan;
- dashboard TU menampilkan indikator nyata Mendekati dan Terlambat serta lima tiket prioritas SLA;
- detail TU menggunakan kalkulator kondisi yang sama dengan halaman pemantauan;
- seluruh fitur mikro-fase ini bersifat baca-saja dan tidak membuat log/notifikasi karena tidak ada perubahan data.

**Pemeriksaan terbatas:**

- file PHP terkait diperiksa sintaksnya;
- query listing dan agregasi dijalankan secara baca-saja terhadap database lokal untuk memastikan struktur SQL valid;
- middleware role, normalisasi filter, status virtual, timezone, pagination, dan ketiadaan mutasi/reminder diinspeksi statis;
- tidak ada test suite, browser automation, data uji, cron, email, atau notifikasi otomatis yang dijalankan.

**Ringkasan handoff:**

- pemantauan mencakup status `DISETUJUI`, `DITUGASKAN`, `DIKERJAKAN`, dan `SELESAI`;
- filter Teknisi mengambil Teknisi yang benar-benar memiliki assignment dalam scope pemantauan;
- tiket tanpa SLA ditampilkan jelas dan tidak menyebabkan perhitungan sisa waktu palsu;
- keterlambatan selalu merupakan indikator turunan dan tidak mengubah status proses tiket;
- kolom `started_at` dan `completed_at` siap digunakan fase pekerjaan Teknisi berikutnya.

**Yang sengaja belum dikerjakan:**

- cron, reminder SLA, email, atau notifikasi keterlambatan;
- dashboard dan daftar tugas Teknisi;
- mulai pekerjaan dan progres;
- laporan ekspor penuh;
- perubahan status otomatis karena terlambat.

**Mikro-fase berikutnya:**

- 7.1 — Dashboard dan Daftar Tugas Teknisi, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 7.1 Dashboard dan Daftar Tugas Teknisi

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/TechnicianTaskController.php`;
- `app/Services/AssignmentPolicy.php`;
- `app/Services/TechnicianDashboardService.php`;
- `app/Services/TechnicianTaskDetailService.php`;
- `app/Views/dashboard/teknisi.php`;
- `app/Views/tickets/technician/index.php`;
- `app/Views/tickets/technician/show.php`.

**File yang diubah:**

- `app/Controllers/DashboardController.php`;
- `app/Models/Assignment.php`;
- `app/Models/TicketFile.php`;
- `app/Services/TicketPolicy.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, atau data awal baru;
- data dashboard, daftar, dan detail bersumber dari `assignments` yang sudah tersedia sejak fase 6.2.

**Route dan hak akses:**

- `GET /teknisi/dashboard` — dashboard nyata khusus role `TEKNISI`;
- `GET /teknisi/tugas` — daftar assignment milik Teknisi login dengan filter status dan kondisi SLA;
- `GET /teknisi/tugas/{assignment_id}` — detail assignment milik Teknisi login;
- `GET /files/ticket/{file_id}` menerima role Teknisi, tetapi policy mensyaratkan assignment milik pengguna dan status dalam siklus kerja Teknisi;
- assignment milik Teknisi lain dikembalikan sebagai tidak ditemukan untuk mencegah pengungkapan data.

**Keputusan teknis:**

- batas kepemilikan diterapkan langsung pada query `assignments.technician_id` dan diverifikasi ulang oleh `AssignmentPolicy`;
- dashboard menghitung tugas baru, sedang dikerjakan, mendekati SLA, terlambat, dan selesai hanya untuk Teknisi login;
- daftar menggunakan pagination sepuluh data serta kondisi SLA virtual yang konsisten dengan pemantauan TU fase 6.3;
- detail menggabungkan tiket, aset, pelapor, penugas TU, SLA, foto kerusakan, dan timeline;
- catatan internal tahapan sebelumnya tidak ditampilkan pada timeline Teknisi; catatan penugasan TU ditampilkan pada panel khusus;
- tombol mulai pekerjaan bersifat nonaktif sebagai kesiapan antarmuka fase 7.2 dan tidak memiliki route mutasi;
- mikro-fase ini sepenuhnya baca-saja: tidak ada update status, `started_at`, log, upload, atau notifikasi baru.

**Pemeriksaan terbatas:**

- seluruh file PHP yang dibuat dan diubah diperiksa sintaksnya;
- query dashboard/listing dijalankan secara baca-saja terhadap database lokal dan berhasil;
- route role, query ownership, policy assignment, serta policy file diinspeksi;
- tidak ada test suite, browser automation, perubahan status, atau data uji yang dijalankan.

**Yang sengaja belum dikerjakan:**

- mulai pekerjaan dan perubahan status menjadi `DIKERJAKAN`;
- pencatatan progres teknisi;
- unggah foto hasil, penyelesaian, dan penutupan tiket;
- reminder otomatis atau mutasi status karena SLA.

**Mikro-fase berikutnya:**

- 7.2 — Mulai Pekerjaan dan Pencatatan Progres, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 7.2 Mulai Pekerjaan dan Progres

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `database/migrations/008_create_work_logs_table.sql`;
- `app/Models/WorkLog.php`;
- `app/Services/WorkExecutionService.php`.

**File yang diubah:**

- `app/Models/Assignment.php`;
- `app/Services/AssignmentPolicy.php`;
- `app/Services/TechnicianTaskDetailService.php`;
- `app/Controllers/TechnicianTaskController.php`;
- `app/Views/tickets/technician/show.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- migration `008_create_work_logs_table.sql` telah diterapkan pada database lokal dan dicatat pada tabel `migrations`;
- tabel `work_logs` memuat `work_log_id`, `assignment_id`, `technician_id`, `progress_status`, `action_taken`, `cost`, `note`, dan `logged_at`;
- tersedia indeks `(assignment_id, logged_at)` dan `technician_id`, foreign key ke assignment serta Teknisi, dan constraint biaya non-negatif;
- `action_taken`, `cost`, dan `note` nullable di database untuk kompatibilitas fase hasil; pada progres 7.2, service tetap mewajibkan `progress_status` dan `note`.

**Route dan hak akses:**

- `POST /teknisi/tugas/{assignment_id}/mulai` — hanya role `TEKNISI` pemilik assignment, dengan CSRF dan status guard;
- `POST /teknisi/tugas/{assignment_id}/progres` — hanya role `TEKNISI` pemilik assignment yang sudah dimulai dan berstatus `DIKERJAKAN`, dengan CSRF;
- route detail 7.1 diselaraskan dengan mekanisme parameter Router melalui `Request::route()`.

**Keputusan teknis:**

- mulai pekerjaan dijalankan dalam transaksi yang mencakup row lock assignment/tiket, guarded update `started_at`, transisi status `DITUGASKAN → DIKERJAKAN`, ticket log, dan notifikasi;
- row lock dan kondisi `started_at IS NULL` mencegah tugas dimulai dua kali termasuk pada permintaan bersamaan;
- pilihan progres 7.2 dibatasi pada Pemeriksaan Awal, Diagnosis Kerusakan, Proses Perbaikan, Menunggu Komponen, dan Pengujian Hasil;
- setiap progres disimpan sebagai `work_logs` dengan `action_taken` serta `cost` kosong, tanpa mengubah status tiket;
- timeline progres diurutkan dari catatan terbaru, terpisah dari timeline transisi tiket;
- notifikasi mulai kerja dan progres dikirim kepada Pegawai pelapor serta TU yang menugaskan;
- kepemilikan diverifikasi pada query dan `AssignmentPolicy`; assignment orang lain tidak dapat dimutasi;
- detail hanya menampilkan form progres ketika status `DIKERJAKAN` dan `started_at` tersedia.

**Pemeriksaan terbatas:**

- file PHP terkait diperiksa sintaksnya;
- keberadaan, struktur kolom, nullable, indeks, constraint, dan record migration `work_logs` diperiksa;
- query baca timeline progres dijalankan tanpa membuat data uji;
- alur CSRF, role, ownership, row lock, status guard, transaksi, audit, dan notifikasi diinspeksi statis;
- tidak ada test suite, browser automation, atau perubahan data tiket/assignment sebagai pengujian.

**Yang sengaja belum dikerjakan:**

- pencatatan `action_taken` dan biaya hasil pekerjaan;
- penandaan hasil siap diselesaikan;
- unggah foto bukti selesai;
- pengisian `completed_at` dan perubahan status menjadi `SELESAI`;
- penutupan tiket atau fitur pembayaran.

**Mikro-fase berikutnya:**

- 7.3 — Hasil Tindakan dan Biaya, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 7.3 Hasil Tindakan dan Biaya

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/WorkResultService.php`;
- `app/Views/tickets/technician/result.php`;
- `app/Views/partials/work-results.php`.

**File yang diubah:**

- `app/Models/WorkLog.php`;
- `app/Services/AssignmentPolicy.php`;
- `app/Services/TechnicianTaskDetailService.php`;
- `app/Services/EmployeeTicketDetailService.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Services/LeaderTicketDetailService.php`;
- `app/Controllers/TechnicianTaskController.php`;
- `app/Views/tickets/technician/show.php`;
- `app/Views/tickets/employee/show.php`;
- `app/Views/tickets/tu/show.php`;
- `app/Views/tickets/leader/show.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, constraint, atau data awal baru;
- menggunakan tabel `work_logs` dari migration 008;
- `action_taken` wajib pada validasi hasil, `cost` tetap decimal nullable dengan constraint non-negatif, dan `note` opsional.

**Route dan hak akses:**

- `GET /teknisi/tugas/{assignment_id}/hasil` — form hasil hanya untuk role `TEKNISI` pemilik assignment yang sedang dikerjakan;
- `POST /teknisi/tugas/{assignment_id}/hasil` — menyimpan hasil dengan CSRF, ownership check, row lock, dan status guard;
- hasil ditampilkan baca-saja pada detail Teknisi, Pegawai pemilik tiket, TU, dan Pimpinan pemutus yang masih memenuhi policy detail masing-masing.

**Keputusan teknis:**

- hasil disimpan sebagai work log dengan status `HASIL_DICATAT` atau `SIAP_BUKTI`; keduanya tidak mengubah status utama tiket;
- tindakan perbaikan wajib dan dibatasi 5.000 karakter, sedangkan catatan tambahan opsional maksimal 2.000 karakter;
- input biaya menerima angka biasa atau format Indonesia seperti `150.000,50`, lalu disimpan sebagai decimal kanonis dengan dua digit pecahan;
- biaya kosong disimpan `NULL`, nilai negatif, format pemisah tidak valid, lebih dari dua digit desimal, dan nilai melebihi kapasitas `DECIMAL(15,2)` ditolak;
- insert work log dan notifikasi Pegawai/TU dijalankan dalam satu transaksi setelah assignment dikunci serta diverifikasi;
- pencatatan hasil tidak membuat ticket log karena tidak ada transisi status; event tetap diaudit kronologis melalui `work_logs`;
- query progres dan hasil dipisahkan berdasarkan nullable `action_taken`, sehingga timeline progres tidak tercampur dengan hasil final;
- hasil terbaru diurutkan pertama dan siap menjadi prasyarat pemeriksaan penutupan pada fase berikutnya;
- pesan UI menegaskan bahwa foto bukti tetap wajib dan tiket belum selesai.

**Pemeriksaan terbatas:**

- seluruh file PHP terkait diperiksa sintaksnya;
- query baca progres dan hasil dijalankan terhadap database lokal tanpa membuat data uji;
- route, CSRF, ownership, status guard, transaksi, format biaya, nullable, notifikasi, dan ketiadaan transisi `SELESAI` diinspeksi;
- tidak ada test suite, browser automation, upload, atau perubahan data tiket/assignment sebagai pengujian.

**Yang sengaja belum dikerjakan:**

- unggah atau penyajian foto `BUKTI_SELESAI`;
- validasi bukti penyelesaian;
- pengisian `assignments.completed_at`;
- perubahan status `DIKERJAKAN → SELESAI`;
- penutupan tiket, pembayaran, invoice, atau vendor.

**Mikro-fase berikutnya:**

- 7.4 — Foto Bukti dan Penutupan Tiket, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 7.4 Foto Bukti dan Penutupan Tiket

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/CompletionService.php`;
- `app/Views/partials/completion-evidence.php`.

**File yang diubah:**

- `app/Services/FileStorageService.php`;
- `app/Models/Assignment.php`;
- `app/Models/WorkLog.php`;
- `app/Services/AssignmentPolicy.php`;
- `app/Services/TechnicianTaskDetailService.php`;
- `app/Services/EmployeeTicketDetailService.php`;
- `app/Services/TuTicketDetailService.php`;
- `app/Services/LeaderTicketDetailService.php`;
- `app/Controllers/TechnicianTaskController.php`;
- `app/Views/tickets/technician/show.php`;
- `app/Views/partials/work-results.php`;
- `app/Views/tickets/employee/show.php`;
- `app/Views/tickets/tu/show.php`;
- `app/Views/tickets/leader/show.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, constraint, atau data awal baru;
- foto menggunakan `ticket_files.file_type = BUKTI_SELESAI`;
- waktu selesai menggunakan kolom `assignments.completed_at` yang tersedia sejak migration 007;
- status akhir menggunakan nilai `SELESAI` yang sudah tersedia pada constraint tiket.

**Route dan hak akses:**

- `POST /teknisi/tugas/{assignment_id}/bukti-selesai` — upload privat khusus Teknisi pemilik dengan tiket `DIKERJAKAN` dan CSRF;
- `POST /teknisi/tugas/{assignment_id}/selesaikan` — penutupan khusus Teknisi pemilik dengan tiket `DIKERJAKAN`, CSRF, ownership, row lock, dan status guard;
- bukti disajikan melalui `GET /files/ticket/{file_id}` yang sudah memakai autentikasi serta `TicketPolicy`;
- hasil dan bukti selesai ditampilkan baca-saja pada detail Teknisi, Pegawai pemilik, TU, dan Pimpinan pemutus.

**Keputusan teknis:**

- upload menerima JPG/JPEG, PNG, dan WEBP, memverifikasi upload asli, MIME, ekstensi, ukuran, serta isi gambar memakai `getimagesize`;
- batas jumlah foto berlaku secara keseluruhan pada tiket, bukan hanya per request;
- file disimpan di `storage/uploads/tickets/YYYY/MM` dengan nama acak dan tidak memiliki URL publik langsung;
- penyimpanan file dan record dijaga konsisten: transaction database di-rollback dan file fisik dihapus bila proses gagal;
- bukti tidak memiliki aksi hapus dari UI, terutama setelah tiket selesai;
- tombol selesai aktif hanya bila ada work log dengan `action_taken`, minimal satu `BUKTI_SELESAI`, dan status masih `DIKERJAKAN`;
- modal konfirmasi mengingatkan bahwa tiket akan menjadi hanya-baca;
- penutupan mengunci assignment/tiket, memvalidasi ulang seluruh syarat, mengisi `completed_at`, guarded update `DIKERJAKAN → SELESAI`, mencatat ticket log, dan membuat notifikasi dalam satu transaksi;
- notifikasi selesai dikirim kepada Pegawai pelapor, TU penugas, dan Pimpinan pemutus;
- `completed_at IS NULL` dan status guard mencegah penutupan ganda termasuk permintaan bersamaan;
- setelah selesai, form progres, hasil, upload, dan tombol penutupan tidak lagi tersedia.

**Pemeriksaan terbatas:**

- seluruh file PHP terkait diperiksa sintaksnya;
- query row lock assignment, keberadaan tindakan, dan jumlah bukti dijalankan secara baca-saja terhadap database lokal;
- route, CSRF, ownership, status guard, private file policy, validasi file, rollback storage, transaksi, audit, notifikasi, dan kondisi hanya-baca diinspeksi;
- tidak ada test suite, browser automation, upload data uji, atau penutupan tiket uji yang dijalankan.

**Yang sengaja belum dikerjakan:**

- validasi ulang atau persetujuan TU setelah tiket selesai;
- pusat notifikasi dan penanda baca;
- pengingat SLA otomatis;
- laporan atau ekspor;
- pembayaran, invoice, vendor, atau penghapusan bukti selesai dari UI.

**Mikro-fase berikutnya:**

- 8.1 — Pusat Notifikasi, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 8.1 Pusat Notifikasi

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/NotificationController.php`;
- `app/Views/notifications/index.php`.

**File yang diubah:**

- `app/Models/Notification.php`;
- `app/Services/NotificationService.php`;
- `app/Controllers/Controller.php`;
- `app/Views/layouts/main.php`;
- `public/assets/css/app.css`;
- `config/routes.php`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, constraint, atau data awal baru;
- tabel `notifications` sudah memiliki `user_id`, `ticket_id`, `notification_type`, `message`, `is_read`, `created_at`, dan `read_at`;
- indeks `idx_notifications_user_unread_created (user_id, is_read, created_at)` serta indeks tiket sudah tersedia dan diverifikasi pada database lokal;
- `read_at` diisi dengan waktu `Asia/Jakarta` ketika notifikasi pertama kali dibaca.

**Route dan hak akses:**

- `GET /notifications` — halaman pusat notifikasi untuk seluruh pengguna terautentikasi;
- `POST /notifications/{notification_id}/read` — menandai satu notifikasi milik pengguna lalu menuju objek terkait;
- `POST /notifications/read-all` — menandai seluruh notifikasi belum dibaca milik pengguna;
- seluruh route mutasi menggunakan CSRF dan query selalu mensyaratkan `notifications.user_id` sama dengan sesi login.

**Keputusan teknis:**

- `Notification` menangani unread count, latest items, pagination, lookup ownership, serta guarded update satu/semua notifikasi;
- ringkasan topbar diinjeksikan oleh base Controller sebelum layout dirender, sehingga view tidak menjalankan query;
- dropdown menampilkan maksimal lima notifikasi terbaru dan badge membatasi teks visual pada `99+`, sementara nilai database tetap utuh;
- halaman lengkap memakai pagination sepuluh item, empty state, serta label tekstual “Belum dibaca” dan “Sudah dibaca” agar status tidak bergantung pada warna;
- membaca notifikasi menggunakan POST, bersifat idempotent untuk item yang sudah dibaca, dan mengisi `read_at` hanya pada perubahan pertama;
- resolver tujuan tidak menerima atau mempercayai URL database; tujuan dibentuk dari role resmi, `ticket_id`, dan `assignment_id` hasil join internal;
- tujuan Pegawai, TU, Pimpinan, dan Teknisi tetap melewati middleware serta policy halaman detail masing-masing;
- tipe notifikasi yang tidak dikenal memakai label aman “Pembaruan Tiket”;
- notifikasi tidak dapat dihapus melalui route atau UI.

**Pemeriksaan terbatas:**

- seluruh file PHP terkait diperiksa sintaksnya;
- query listing, unread count, join assignment, pagination, dan resolver dijalankan secara baca-saja terhadap database lokal;
- indeks komposit notifikasi diverifikasi memiliki tiga kolom;
- route, autentikasi, CSRF, ownership update, escaping pesan, dan ketiadaan delete diinspeksi;
- tidak ada test suite, browser automation, perubahan status baca data nyata, atau pembuatan notifikasi uji.

**Yang sengaja belum dikerjakan:**

- email, push browser, WhatsApp, atau channel eksternal;
- cron, reminder SLA, dan notifikasi keterlambatan otomatis;
- retry atau delivery log channel eksternal;
- penghapusan dan pengarsipan notifikasi;
- laporan atau ekspor.

**Mikro-fase berikutnya:**

- 8.2 — Pengingat SLA Otomatis, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 8.2 Pengingat SLA Otomatis

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Console/SlaReminderCommand.php`;
- `app/Services/SlaReminderService.php`;
- `bin/sla-reminders.php`;
- `database/migrations/009_add_notification_event_key.sql`.

**File yang diubah:**

- `.gitignore`;
- `app/Models/Notification.php`;
- `app/Models/SlaMonitoring.php`;
- `app/Services/NotificationService.php`;
- `app/Services/SlaMonitoringService.php`;
- `database/database.sql`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- kolom teknis nullable `notifications.event_key VARCHAR(100)` ditambahkan melalui migration 009;
- unique key `uq_notifications_user_ticket_event (user_id, ticket_id, event_key)` menjamin deduplikasi atomik tanpa memengaruhi notifikasi lama yang memiliki `event_key = NULL`;
- migration 009 telah diterapkan dan dicatat pada database lokal.

**Route dan hak akses:**

- tidak ada route HTTP baru;
- entry point `php bin/sla-reminders.php` menolak eksekusi non-CLI;
- file lock mencegah dua proses scheduler berjalan bersamaan.

**Keputusan teknis:**

- jendela mendekati tenggat konsisten dengan pemantauan SLA, yaitu 24 jam sebelum `sla_due_at`;
- notifikasi mendekati tenggat dibuat satu kali per nilai SLA dengan event `SLA_NEAR:<waktu-sla>`;
- peringatan terlambat dibuat maksimal satu kali per hari dengan event `SLA_OVERDUE:<tanggal-WIB>` agar pengingat dapat berulang secara terkendali;
- penerima mendekati tenggat adalah seluruh akun TU aktif dan Teknisi aktif yang ditugaskan;
- Pimpinan aktif yang menyetujui tiket ikut menerima peringatan ketika tiket terlambat;
- kandidat dikunci dan diperiksa ulang di dalam transaksi sebelum notifikasi dibuat, sehingga tiket yang sudah `SELESAI` tidak diproses;
- tidak ada perubahan `tickets.status`, `sla_due_at`, assignment, atau ticket log karena reminder bukan transisi proses;
- waktu command dan event memakai `Asia/Jakarta`;
- ringkasan eksekusi dicatat tanpa data tiket atau pengguna ke `storage/logs/app.log`;
- konfigurasi cron Linux dan Windows Task Scheduler didokumentasikan pada README.

**Pemeriksaan terbatas:**

- file PHP terkait diperiksa sintaksnya;
- kolom, unique key, dan catatan migration diverifikasi pada database lokal;
- query kandidat SLA dijalankan secara baca-saja;
- command tidak dijalankan terhadap data nyata agar tidak membuat notifikasi pengujian;
- tidak ada test suite atau testing cron berulang yang dibuat maupun dijalankan.

**Yang sengaja belum dikerjakan:**

- email SMTP, WhatsApp, browser push, atau kanal eksternal;
- perubahan SLA dan status `TERLAMBAT`;
- dashboard operasional, laporan, ekspor, riwayat aset, dan audit trail fase berikutnya;
- konfigurasi scheduler production secara langsung pada sistem operasi.

**Mikro-fase berikutnya:**

- 9.1 — Dashboard Operasional Berbasis Data, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 9.1 Dashboard Operasional Berbasis Data

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- tidak ada.

**File yang diubah:**

- `app/Controllers/DashboardController.php`;
- `app/Models/Ticket.php`;
- `app/Services/LeaderDashboardService.php`;
- `app/Views/dashboard/index.php`;
- `app/Views/dashboard/pegawai.php`;
- `app/Views/dashboard/tu.php`;
- `app/Views/dashboard/pimpinan.php`;
- `app/Views/dashboard/teknisi.php`;
- `app/Views/layouts/main.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, constraint, atau data awal baru;
- query menggunakan indeks status tiket, pelapor tiket, approver, dan Teknisi yang sudah tersedia.

**Route dan hak akses:**

- tidak ada route baru;
- `GET /pegawai/dashboard` tetap khusus Pegawai dan seluruh datanya dibatasi `tickets.reported_by`;
- `GET /tu/dashboard` tetap khusus TU dan menampilkan data operasional lintas tiket sesuai kewenangan TU;
- `GET /pimpinan/dashboard` tetap khusus Pimpinan; antrean bersifat role-wide, sedangkan keputusan dan penyelesaian dibatasi `approvals.approver_id` pengguna login;
- `GET /teknisi/dashboard` tetap khusus Teknisi dan seluruh tugas dibatasi `assignments.technician_id`.

**Keputusan teknis:**

- agregasi kartu tetap digabung dalam query statistik per domain dan tidak membuat satu query per kartu;
- kartu Pegawai menautkan seluruh tiket, revisi, proses, dan selesai ke daftar tiket miliknya;
- kartu TU menampilkan perlu diperiksa, menunggu keputusan, menunggu SLA, mendekati tenggat, dan terlambat;
- dashboard TU menampilkan maksimal lima tiket yang sedang menunggu keputusan Pimpinan dan menautkannya ke detail TU;
- kartu Pimpinan mengganti metrik mendesak dengan ringkasan tiket selesai yang sebelumnya disetujui oleh Pimpinan login;
- jumlah setuju dan tolak Pimpinan juga dibatasi pada keputusan pengguna login agar konsisten dengan policy riwayat keputusan;
- kartu Teknisi menautkan filter status atau kondisi SLA pada daftar tugas miliknya;
- seluruh kartu dapat difokuskan keyboard, memiliki label aksesibel, dan tetap satu kolom pada layar hingga 480 piksel;
- view dashboard generik lama tidak lagi menampilkan placeholder atau angka statis;
- tidak ada cache atau dependensi visual baru karena query yang ada masih ringan.

**Pemeriksaan terbatas:**

- file PHP terkait diperiksa sintaksnya;
- service dashboard empat role dijalankan dengan query read-only terhadap akun aktif lokal;
- hasil statistik Pegawai dan Teknisi diverifikasi tetap memiliki filter kepemilikan;
- tautan kartu, escaping output, empty state, dan breakpoint responsif diinspeksi;
- tidak ada test suite, browser automation, atau perubahan data sebagai pengujian.

**Yang sengaja belum dikerjakan:**

- laporan, filter laporan, ekspor CSV/XLS/PDF, dan chart kompleks;
- riwayat aset serta audit trail lintas modul;
- cache dashboard, AI analytics, atau library frontend baru.

**Mikro-fase berikutnya:**

- 9.2 — Laporan, Filter, dan Ekspor, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 9.2 Laporan, Filter, dan Ekspor

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/ReportController.php`;
- `app/Models/Report.php`;
- `app/Services/ReportFilter.php`;
- `app/Services/ReportPolicy.php`;
- `app/Services/ReportService.php`;
- `app/Services/CsvExportService.php`;
- `app/Views/reports/index.php`;
- `database/migrations/010_add_ticket_report_index.sql`.

**File yang diubah:**

- `app/Core/Response.php`;
- `app/Views/layouts/main.php`;
- `config/routes.php`;
- `database/database.sql`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada tabel, kolom, constraint, atau data awal baru;
- migration 010 menambahkan indeks `idx_tickets_created_at (created_at)` untuk filter periode laporan;
- migration 010 telah diterapkan dan dicatat pada database lokal;
- hasil laporan tidak disimpan permanen.

**Route dan hak akses:**

- `GET /tu/laporan` — hanya role TU;
- `GET /tu/laporan/export.csv` — hanya role TU;
- `GET /pimpinan/laporan` — hanya role Pimpinan;
- `GET /pimpinan/laporan/export.csv` — hanya role Pimpinan;
- seluruh route dilindungi auth, role middleware, dan pemeriksaan ulang `ReportPolicy` pada controller;
- Pegawai dan Teknisi tidak mendapat menu maupun akses route laporan.

**Keputusan teknis:**

- periode laporan menggunakan `tickets.created_at`, default hari pertama bulan berjalan sampai hari ini dalam zona waktu `Asia/Jakarta`;
- filter mencakup status, aset, `category_issue`, unit pelapor, Teknisi, serta kondisi SLA;
- klasifikasi SLA adalah `TEPAT_WAKTU`, `TERLAMBAT`, dan `BELUM_ADA_SLA` tanpa menambah status proses tiket;
- tiket aktif dengan SLA yang belum lewat masuk tepat waktu/masih aman; tiket aktif lewat SLA atau tiket selesai setelah SLA masuk terlambat;
- biaya dijumlahkan dari `work_logs.cost` per assignment melalui subquery agregat agar satu tiket tetap menghasilkan satu baris;
- layar memakai pagination 15 baris, sedangkan ekspor membaca data dalam batch maksimal 500 baris;
- CSV memakai delimiter titik koma, BOM UTF-8, metadata waktu/pembuat/role/filter, dan prefix apostrof untuk sel yang berpotensi menjadi formula;
- session lock dilepas sebelum streaming CSV agar unduhan tidak memblokir request pengguna lain pada sesi yang sama;
- filter layar dan CSV menggunakan validator serta query yang sama;
- PDF tidak dibuat karena tidak ada pustaka PDF dan prompt melarang penambahan dependensi berat tanpa kebutuhan nyata;
- Pimpinan mendapat laporan read-only; tautan detail langsung hanya ditampilkan bagi TU karena policy detail Pimpinan dibatasi konteks keputusan.

**Pemeriksaan terbatas:**

- seluruh file PHP terkait diperiksa sintaksnya;
- query default bulan berjalan, filter status, ringkasan biaya/SLA, dan generator ekspor dijalankan secara read-only pada database lokal;
- validasi tanggal awal melewati tanggal akhir menghasilkan error;
- indeks periode dan catatan migration diverifikasi;
- route, middleware, policy, escaping output, pagination, kesamaan filter, dan mitigasi formula injection diinspeksi;
- tidak ada test suite, browser automation, atau perubahan data sebagai pengujian.

**Yang sengaja belum dikerjakan:**

- ekspor PDF, XLS/XLSX, chart BI, dan penyimpanan hasil laporan;
- akuntansi resmi, pembayaran, pengadaan, atau integrasi SIMAK-BMN;
- riwayat per aset dan halaman audit trail lintas tiket.

**Mikro-fase berikutnya:**

- 9.3 — Riwayat Aset dan Audit Trail, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 9.3 Riwayat Aset dan Audit Trail

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Controllers/AssetHistoryController.php`;
- `app/Controllers/AuditTrailController.php`;
- `app/Services/AssetHistoryService.php`;
- `app/Services/AuditTrailService.php`;
- `app/Views/assets/index.php`;
- `app/Views/assets/history.php`;
- `app/Views/audit/index.php`.

**File yang diubah:**

- `app/Models/Asset.php`;
- `app/Models/TicketLog.php`;
- `app/Services/TicketPolicy.php`;
- `app/Services/ReportService.php`;
- `app/Views/layouts/main.php`;
- `app/Views/reports/index.php`;
- `app/Views/tickets/tu/show.php`;
- `app/Views/tickets/leader/show.php`;
- `config/routes.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, constraint, atau data awal baru;
- indeks wajib sudah tersedia: `uq_assets_asset_code`, `idx_tickets_asset_id`, `idx_ticket_logs_ticket_id`, dan `idx_ticket_logs_ticket_changed_at`;
- seluruh query mikro-fase bersifat baca-saja.

**Route dan hak akses:**

- `GET /tu/aset` — hanya TU;
- `GET /tu/aset/{asset_id}/riwayat` — hanya TU;
- `GET /tu/tiket/{ticket_id}/audit` — hanya TU;
- `GET /pimpinan/aset/{asset_id}/riwayat` — hanya Pimpinan;
- `GET /pimpinan/tiket/{ticket_id}/audit` — hanya Pimpinan sebagai route pendamping untuk kebutuhan audit penuh;
- seluruh route dilindungi auth, role middleware, dan pemeriksaan ulang `TicketPolicy`;
- Pegawai dan Teknisi tidak mendapat route audit penuh.

**Keputusan teknis:**

- daftar aset hanya tersedia bagi TU dan tidak menyediakan operasi tambah, ubah, atau hapus;
- Pimpinan membuka riwayat aset dari tautan aset pada laporan agar tidak dibuatkan modul pengelolaan aset;
- riwayat tiket aset diurutkan terbaru lebih dahulu, sedangkan audit per tiket diurutkan kronologis dari log pertama;
- ringkasan aset menghitung tiket total, aktif, selesai, ditolak, serta frekuensi kategori isu;
- biaya tiket berasal dari agregasi `work_logs.cost`, konsisten dengan laporan fase 9.2;
- filter audit menerima periode opsional, pelaku yang benar-benar terdapat pada tiket, dan status tujuan resmi;
- nama, role, serta unit pelaku ditampilkan, tetapi username, password, token, dan data sensitif lain tidak disertakan;
- seluruh audit read-only dan tidak memiliki route edit/delete.

**Pemeriksaan terbatas:**

- file PHP baru dan konfigurasi route diperiksa sintaksnya;
- keberadaan indeks wajib diverifikasi dari schema dan migration yang sudah ada;
- tidak ada test suite, browser automation, atau perubahan data sebagai pengujian.

**Yang sengaja belum dikerjakan:**

- CRUD aset lengkap, perubahan/penghapusan audit, dan analitik prediktif;
- hardening keamanan, backup/restore, deployment, dan fitur mikro-fase 10.1 atau sesudahnya.

**Mikro-fase berikutnya:**

- 10.1 — Hardening Keamanan, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 10.1 Integrasi Akhir dan Hardening

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `app/Services/SessionGuardService.php`.

**File yang diubah:**

- `app/Core/Response.php`;
- `app/Middleware/AuthMiddleware.php`;
- `app/Middleware/GuestMiddleware.php`;
- `app/Models/User.php`;
- `app/Services/AuthService.php`;
- `app/Services/Logger.php`;
- `app/Services/SessionManager.php`;
- `app/Views/layouts/main.php`;
- `database/database.sql`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration baru dan tidak ada perubahan pada database lokal;
- definisi tabel `work_logs` dari migration 008 ditambahkan ke baseline `database/database.sql` yang sebelumnya tertinggal;
- tabel tetap memiliki foreign key ke `assignments` dan `users`, indeks `(assignment_id, logged_at)`, indeks Teknisi, serta check biaya nonnegatif;
- tidak ada reset, penghapusan, atau migration destruktif.

**Route dan hak akses:**

- tidak ada route baru atau perubahan role route;
- seluruh GET telah diaudit tidak melakukan perubahan data;
- seluruh POST tetap dilindungi autentikasi/role sesuai konteks dan validasi CSRF pada controller;
- route Pegawai tetap memakai kepemilikan `reported_by`, sedangkan route Teknisi memakai `technician_id` baik pada query detail maupun row lock;
- file privat tetap hanya dapat diakses melalui `GET /files/ticket/{file_id}` dengan policy per role dan ownership;
- sesi pada route terautentikasi sekarang juga memverifikasi akun masih aktif serta username/role belum berubah.

**Keputusan teknis:**

- validasi identitas sesi ditempatkan pada `SessionGuardService` dan dipakai middleware auth/guest agar tidak mencampurkan query ke view atau controller;
- perubahan nama/unit dari database dapat disegarkan pada sesi, tetapi perubahan username/role atau deaktivasi akun memaksa login ulang;
- login dan perubahan kata sandi merotasi session ID serta token CSRF untuk memperkecil risiko fixation dan penggunaan token lama;
- CSRF controller dipertahankan agar flash message dan tujuan redirect tiap form tidak berubah;
- header respons diperkuat dengan CSP yang hanya mengizinkan origin aplikasi dan CDN Bootstrap resmi yang telah digunakan proyek, `form-action self`, anti-object, anti-framing, permission policy, dan cache `no-store`;
- HSTS hanya dikirim bila PHP menerima request HTTPS agar development HTTP tidak terkunci;
- logger meredaksi key sensitif secara rekursif serta pola credential/Bearer pada string, termasuk jalur fallback `error_log`;
- validasi upload yang ada dinyatakan konsisten: jumlah/ukuran, `is_uploaded_file`, MIME `finfo`, kecocokan ekstensi, `getimagesize`, nama acak, penyimpanan privat, dan realpath containment;
- transaksi status telah diaudit memakai row lock/status guard, ticket log, notifikasi, commit, dan rollback dalam service terkait;
- label placeholder `Segera` untuk role tidak resmi dihapus karena sistem hanya mengizinkan empat role resmi;
- tidak ditambahkan dependensi, module bisnis, atau refactor arsitektur besar.

**Pemeriksaan terbatas:**

- pemetaan route GET/POST, middleware, CSRF, dan form diperiksa secara statis;
- query ownership Pegawai/Teknisi, policy file, penyimpanan privat, serta service transaksi diperiksa;
- konstanta status dibandingkan dengan constraint schema dan seluruh nilai tetap konsisten;
- file PHP yang berubah diperiksa sintaksnya;
- tidak ada test suite, browser automation, upload uji, atau perubahan data bisnis.

**Yang sengaja belum dikerjakan:**

- dokumentasi deployment production lengkap, checklist UAT, backup/restore operasional, dan konfigurasi web server production;
- rate limiting terdistribusi, SSO, MFA, SIEM, WAF, atau integrasi keamanan eksternal;
- fitur bisnis baru, redesign, dan seluruh pekerjaan mikro-fase 10.2.

**Mikro-fase berikutnya:**

- 10.2 — Dokumentasi Deployment dan Persiapan UAT, hanya setelah instruksi eksplisit.

### 3 Agustus 2026 — Mikro-Fase 10.2 Dokumentasi, Deployment, dan Persiapan UAT

**Model/agent:** Codex (GPT-5)

**Status:** Selesai

**File yang dibuat:**

- `docs/23-PANDUAN-PENGGUNA-EMPAT-ROLE.md`;
- `docs/24-DEPLOYMENT-BACKUP-DAN-RECOVERY.md`;
- `docs/25-SKENARIO-BLACK-BOX-DAN-UAT.md`;
- `docs/26-CHECKLIST-BUKTI-BAB-IV.md`;
- `docs/27-DATA-AWAL-DAN-AKUN-PRODUKSI.md`.

**File yang diubah:**

- `README.md`;
- `docs/22-MANIFEST.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database:**

- tidak ada migration, tabel, kolom, indeks, constraint, seeder, atau perubahan data;
- instalasi baru didokumentasikan menggunakan baseline `database/database.sql` satu kali;
- upgrade database lama didokumentasikan memakai migration 001–010 secara berurutan dan hanya untuk file yang belum diterapkan;
- migration 009/010 ditegaskan tidak boleh dijalankan ulang;
- seeder development dan seluruh data demo dilarang digunakan pada produksi;
- backup database, upload privat, `.env` terenkripsi, konfigurasi server, restore, dan verifikasi recovery telah didokumentasikan.

**Route dan hak akses:**

- tidak ada route atau perubahan hak akses baru;
- route utama per role dijelaskan melalui panduan pengguna dan matriks pengujian tanpa hostname/credential produksi;
- skenario negatif mencakup akses lintas role, ownership Pegawai, ownership Teknisi, file privat, audit penuh, CSRF, dan session invalid;
- seluruh panduan tetap memakai empat role resmi tanpa role Admin.

**Keputusan teknis:**

- dokumentasi operasional dipisah berdasarkan audiens: pengguna, operator deployment, penguji UAT, penulis Bab IV, dan pengelola data awal;
- production direkomendasikan memakai document root `public/`, HTTPS, `APP_DEBUG=false`, user database hak minimal, dan folder storage terpilih yang writable;
- SMTP dinyatakan tidak digunakan agar operator tidak menyiapkan konfigurasi yang tidak didukung aplikasi;
- ketergantungan CDN Bootstrap dijelaskan sebagai kebutuhan akses jaringan internal;
- backup meminta password database secara interaktif, tidak menaruh rahasia pada command atau script;
- restore wajib memulihkan upload ke path sama agar `ticket_files.file_path` tetap valid;
- repository tidak diberi seeder akun produksi untuk mencegah identitas/password organisasi masuk source code;
- UAT dirancang untuk lingkungan terpisah dengan data fiktif, minimal dua Pegawai/Teknisi untuk pengujian ownership, dan bukti tanpa rahasia;
- screenshot Bab IV mencakup seluruh alur, empat role, keamanan, laporan, audit, dan tampilan 360 piksel;
- tidak ada script deployment/backup baru karena prosedur berbeda antarserver dan shell script bercredential berisiko disalahgunakan.

**Pemeriksaan terbatas:**

- nama file, route, role, urutan migration, tabel inti, command SLA, konfigurasi upload, dan perilaku modul dicocokkan dengan implementasi;
- dokumen diperiksa secara statis untuk placeholder credential dan larangan data demo produksi;
- tidak ada test suite, seluruh test case, browser automation, perubahan data, scheduler, backup, restore, atau deployment nyata yang dijalankan.

**Yang sengaja belum dikerjakan:**

- pelaksanaan serta penandatanganan UAT oleh pengguna nyata;
- pengambilan screenshot Bab IV;
- provisioning akun/aset produksi, deployment server, konfigurasi DNS/sertifikat, scheduler OS, backup, dan restore nyata;
- penetapan hostname, credential, retention backup, RPO/RTO, kontak operator, dan kebijakan keamanan organisasi;
- fitur bisnis, integrasi eksternal, atau fase lanjutan di luar roadmap.

**Mikro-fase berikutnya:**

- tidak ada mikro-fase berikutnya pada roadmap saat ini; menunggu validasi manual dan instruksi eksplisit.

### 4 Agustus 2026 — Production Readiness Pasca-Roadmap

**Model/agent:** Codex (GPT-5)

**Status:** Implementasi source code selesai; aktivasi produksi menunggu konfigurasi server, penggantian data demo, dan UAT.

**File yang dibuat:**

- `.env.production.example`;
- `app/Services/ProductionConfiguration.php`;
- `app/Services/LoginThrottleService.php`;
- `app/Services/ProductionReadinessService.php`;
- `bin/production-check.php`;
- `deploy/apache/bkkbn-eticketing.conf.example`;
- `deploy/php/production.ini.example`;
- `docs/28-PRODUCTION-READINESS.md`.

**File yang diubah:**

- `.env.example`;
- `app/Controllers/AuthController.php`;
- `app/Controllers/ProfileController.php`;
- `app/Services/AuthService.php`;
- `app/Services/SessionManager.php`;
- `app/Views/layouts/auth.php`;
- `app/Views/layouts/main.php`;
- `bin/sla-reminders.php`;
- `bootstrap/app.php`;
- `composer.json` dan `composer.lock`;
- `config/app.php`;
- `README.md`;
- `docs/22-MANIFEST.md`;
- `docs/24-DEPLOYMENT-BACKUP-DAN-RECOVERY.md`;
- `docs/06-STATUS-PROJECT.md`.

**Perubahan database dan route:**

- tidak ada migration, perubahan schema, reset, atau perubahan data;
- tidak ada route baru atau perubahan matriks hak akses;
- pemeriksa kesiapan hanya membaca konfigurasi, permission, schema, indeks, role, dan data demo;
- login kini dibatasi secara lokal per kombinasi username dan alamat IP tanpa menyimpan nilai mentahnya.

**Keputusan teknis:**

- bootstrap production bersifat fail-closed untuk HTTPS, debug, credential database, timezone, batas upload, konfigurasi throttle, dan log level yang tidak aman;
- session cookie production selalu `Secure`, umur garbage collection diselaraskan dengan timeout aplikasi, dan session ID diperkuat;
- kegagalan login dibatasi menggunakan file privat di `storage/cache/login-throttle`, sementara keberhasilan login membersihkan hitungan terkait;
- password yang berhasil diverifikasi otomatis di-rehash ketika parameter algoritma PHP berubah;
- Bootstrap CDN memakai Subresource Integrity dan `crossorigin`;
- Composer sekarang mendeklarasikan ekstensi PHP runtime yang wajib dan menyediakan command `composer production-check`;
- template production sengaja memakai placeholder yang tidak lolos validasi sampai operator mengisinya dengan nilai server sebenarnya;
- file `.env` development yang sedang digunakan tidak diubah dan tidak dianggap sebagai konfigurasi produksi.

**Verifikasi yang dijalankan:**

- lint terhadap 139 file PHP: lulus;
- `composer validate --strict`: lulus;
- `composer audit --locked`: tidak menemukan advisory keamanan;
- pemeriksa production: 21 PASS dan 2 FAIL pada environment lokal, yaitu `APP_ENV` belum `production` dan akun demo masih tersedia; hasil ini sesuai guard yang dirancang.

**Yang masih wajib dilakukan operator sebelum go-live:**

- salin dan isi `.env.production.example` memakai hostname serta secret produksi nyata;
- provision Apache/PHP, HTTPS, database least-privilege, scheduler SLA, backup, dan monitoring;
- hapus atau nonaktifkan seluruh akun demo lalu buat akun serta aset produksi resmi;
- jalankan `composer production-check` sampai tidak ada FAIL;
- laksanakan UAT, backup/restore drill, dan persetujuan go-live sesuai dokumentasi fase 10.2;
- aplikasi belum diklaim telah ter-deploy ke server produksi karena akses dan parameter infrastrukturnya tidak tersedia di repository.

### 4 Agustus 2026 — Penetapan Status Siap Produksi

**Status:** Siap Produksi

**Konfirmasi pengguna:**

- testing manual telah selesai dan aplikasi dinyatakan siap produksi;
- penanda fase pengembangan di antarmuka aplikasi dihapus;
- kartu `Mikro-Fase Aktif / Integrasi & Hardening / Fase 10.1` dihapus dari sidebar;
- teks berorientasi fase pada halaman beranda, SLA, penugasan, detail tiket Pegawai, dan halaman error diganti dengan istilah operasional;
- riwayat implementasi pada dokumen status tetap dipertahankan sebagai audit trail proyek.

**File yang diubah:**

- `app/Views/layouts/main.php`;
- `app/Views/home/index.php`;
- `app/Views/errors/500.php`;
- `app/Views/tickets/tu/sla.php`;
- `app/Views/tickets/tu/assignment.php`;
- `app/Views/tickets/employee/show.php`;
- `public/assets/css/app.css`;
- `README.md`;
- `docs/06-STATUS-PROJECT.md`.
