# User Requirements Tracker

Rujukan utama untuk UR-01 hingga UR-25. Kemas kini setiap kali satu UR bergerak.
Semakan terakhir: 2026-10-01

Ringkasan: 25 Ada, 0 Separa, 0 Belum

## Status

| No.   | Requirement               | Status | Fasa |
|-------|---------------------------|--------|------|
| UR-01 | Login & Authentication    | Ada    | 1    |
| UR-02 | Role-Based Access Control | Ada    | 1    |
| UR-03 | User Profile              | Ada    | 1    |
| UR-04 | Dashboard                 | Ada    | -    |
| UR-05 | Course Management         | Ada    | 2    |
| UR-06 | Course Catalogue          | Ada    | -    |
| UR-07 | Course Registration       | Ada    | 3    |
| UR-08 | Learning Material         | Ada    | 2    |
| UR-09 | Online Learning           | Ada    | -    |
| UR-10 | Quiz / Assessment         | Ada    | -    |
| UR-11 | Passing Criteria          | Ada    | 2    |
| UR-12 | Attendance                | Ada    | 3    |
| UR-13 | Training History          | Ada    | 2    |
| UR-14 | Learning Progress         | Ada    | -    |
| UR-15 | Certificate               | Ada    | -    |
| UR-16 | Notification              | Ada    | 4    |
| UR-17 | Training Calendar         | Ada    | 3    |
| UR-18 | Instructor/Trainer        | Ada    | 3    |
| UR-19 | Feedback                  | Ada    | 4    |
| UR-20 | Reports                   | Ada    | -    |
| UR-21 | Search & Filter           | Ada    | 2    |
| UR-22 | Audit Trail               | Ada    | 5    |
| UR-23 | Data Export               | Ada    | 5    |
| UR-24 | System Administration     | Ada    | 1, 2 |
| UR-25 | Security & Backup         | Ada    | 5    |

Status: Ada = siap, Separa = sebahagian, Belum = belum mula, WIP = sedang dibuat

## Fasa

| Fasa | Fokus                 | UR                     | Status            |
|------|-----------------------|------------------------|-------------------|
| 1    | Asas pengguna & admin | 01, 02, 03, 24         | Siap (2026-09-28) |
| 2    | Kandungan & penilaian | 05, 08, 11, 13, 21, 24 | Siap (2026-09-28) |
| 3    | Latihan bersemuka     | 07, 12, 17, 18         | Siap (2026-09-28) |
| 4    | Penglibatan           | 16, 19                 | Siap (2026-10-01) |
| 5    | Operasi & pematuhan   | 22, 23, 25             | Siap (2026-10-01) |

- Migration LMS boleh terus dijalankan tanpa tanya (kebenaran 2026-09-28). Operasi yang buang data tetap perlu tanya.

## Tugasan tertunda (buat dulu sesi seterusnya)

1. Lesson video/gambar dan cover kursus disimpan di disk `public`: sesiapa yang ada URL boleh buka tanpa login (lampiran fail dah private). Tunggu keputusan user.
2. Server: jadualkan `php artisan schedule:run` setiap minit (cron / Windows Task Scheduler) untuk backup harian. Set `BACKUP_MYSQLDUMP` dalam `.env` server.
3. Production `.env`: `APP_ENV=production`, `APP_DEBUG=false`, `LOG_LEVEL=warning`, `SESSION_SECURE_COOKIE=true` (HTTPS).
4. **Email (UR-16): HOLD, buat paling akhir** (keputusan user 2026-10-01). Perlu SMTP, kemudian tambah `mail` dalam `LmsNotice::via()`. Peringatan sesi H-1 juga perlu scheduler.

## Butiran setiap UR

### UR-01 Login & Authentication (Ada)
- Login guna ID staf atau email dalam satu field (`LoginRequest`), tak kisah huruf besar/kecil.
- Register awam dibuang. Admin cipta akaun.
- Akaun nonaktif tak boleh login dan di-logout serta-merta (`EnsureActive`).
- Reset password dan throttle login (Breeze).

### UR-02 Role-Based Access Control (Ada)
- Role `admin` / `instructor` / `employee` (`User::ROLES`), middleware `role:` (`EnsureRole`).
- Users, Departments, Settings, Enrollments: admin sahaja (ada test).

### UR-03 User Profile (Ada)
- Papar rekod staf (ID staf, jabatan, role), read-only.
- Staf boleh ubah nama, email, jawatan, telefon, password.
- "Delete account" dibuang.

### UR-04 Dashboard (Ada)
- Stats, progress, status kursus, leaderboard, angka pasukan untuk admin/instructor.

### UR-05 Course Management (Ada)
- CRUD kursus, cover image, markah lulus.
- Aktif/nyahaktif: label Active/Inactive (pilihan A, tiada schema baru).
- Kursus Inactive hilang dari Browse. Staf yang dah berdaftar kekal rekod dan sijil.

### UR-06 Course Catalogue (Ada)
- `/browse`, cadangan ikut jabatan, simpan kursus.

### UR-07 Course Registration (Ada)
- Staf daftar sendiri, admin daftarkan staf.
- Kursus boleh ditanda "Needs approval" (`courses.requires_approval`): staf klik "Request to join", admin luluskan/tolak di `/requests` (`EnrollmentRequest`).
- Katalog tunjuk "Awaiting approval" semasa menunggu.

### UR-08 Learning Material (Ada)
- Teks, video (upload/URL), gambar.
- Lampiran PDF/PPT/Word/Excel/TXT/ZIP, max 50 MB (`lesson_files`, disk private).
- Download melalui `/files/{id}`: staf berdaftar, pemilik kursus dan admin sahaja.

### UR-09 Online Learning (Ada)
- Modul -> lesson, tanda selesai, lesson dikunci ikut turutan.

### UR-10 Quiz / Assessment (Ada)
- Kuiz modul + penilaian akhir, MCQ, boleh cuba semula.

### UR-11 Passing Criteria (Ada)
- `courses.pass_mark` ikut kursus, diset dalam editor kursus.
- Kursus baru ambil default dari Settings.
- Nota: tukar markah tak menilai semula percubaan lama.

### UR-12 Attendance (Ada)
- Staf yang berdaftar dengan kursus boleh register sesi (had tempat, tutup bila sesi mula).
- Admin / pemilik kursus tanda Present / Absent di halaman sesi (`session_attendees.attended`).
- Rekod kehadiran keluar dalam Training history (staf dan admin).
- Nota: kehadiran belum dikira dalam syarat siap kursus / sijil.

### UR-13 Training History (Ada)
- `/history` untuk staf: tarikh daftar, progress, tarikh siap, markah terbaik, percubaan, link sijil.
- Admin nampak sejarah staf di `/users/{id}` (`User::trainingHistory()`).
- Termasuk jadual sesi bersemuka dan kehadiran.

### UR-14 Learning Progress (Ada)
- % ikut lesson + kuiz (`Enrollment::progress`).
- `enrollments.completed_at` diisi bila kursus siap.

### UR-15 Certificate (Ada)
- Sijil boleh cetak, nombor siri (prefix dari Settings), nama organisasi dari Settings.
- Kurang: tiada download PDF sebenar (guna print browser).

### UR-16 Notification (Ada)
- In-app sahaja (channel `database`, table `notifications`), satu class `LmsNotice` (mesej + link).
- Loceng di top bar dengan kiraan belum baca, halaman `/notifications`, klik = tanda dibaca + ikut link, "Mark all as read".
- Dihantar bila: staf minta sertai (ke semua admin), permohonan lulus/tolak, admin daftarkan staf, sesi baru (ke staf berdaftar kursus), sesi tukar masa/lokasi atau dibatalkan (ke peserta sesi), kursus siap (sijil sedia), maklum balas baru (ke pemilik kursus).
- Kurang: email, peringatan sesi automatik.

### UR-17 Training Calendar (Ada)
- `/calendar`: paparan bulan (desktop), senarai agenda (mobile), tanda sesi yang staf dah register.
- Sesi (`training_sessions`): kursus, tajuk, tarikh, masa, lokasi, trainer, had tempat, nota.
- Admin / instructor jadualkan sesi dari kalendar atau editor kursus.
- Sesi juga keluar di halaman kursus staf.

### UR-18 Instructor/Trainer (Ada)
- `/trainers` (admin): trainer dalaman (link ke akaun instructor/admin) atau penceramah luar (organisasi).
- Profil: kepakaran, bio, email, telefon, aktif/tidak. Profil keluar di halaman sesi.

### UR-19 Feedback (Ada)
- Staf yang siap kursus beri rating 1-5 + komen (`course_feedback`, satu setiap staf setiap kursus, boleh dikemas kini) di halaman kursus.
- Admin / pemilik kursus nampak purata, taburan dan senarai komen di editor kursus (`#feedback`).
- Kurang: maklum balas untuk sesi bersemuka.

### UR-20 Reports (Ada)
- Laporan ikut jabatan/kursus/status (`ReportController`), export CSV.

### UR-21 Search & Filter (Ada)
- Server-side: Users, Enrollments (nama/ID staf/email, kursus, jabatan, status), Reports.
- Client-side: Browse, Courses, Training history.

### UR-22 Audit Trail (Ada)
- Table `audit_logs` (append-only): siapa, tindakan, rekod, medan berubah (lama -> baru), IP, masa.
- Trait `Auditable` pada User, Course, Module, Lesson, LessonFile, Question, Enrollment, EnrollmentRequest, TrainingSession, Trainer, Department, Setting. Password direkod sebagai `•••`.
- Log masuk / keluar / gagal log masuk (event auth dalam `AppServiceProvider`), dan setiap backup.
- `/audit` (admin): carian, tapis ikut user, tindakan, tarikh; export CSV/Excel.
- Tidak direkod: lesson progress, quiz attempt, pendaftaran & kehadiran sesi (pivot). Tiada polisi retention.

### UR-23 Data Export (Ada)
- CSV + Excel (`phpoffice/phpspreadsheet`) melalui `App\Support\Export`, komponen `x-export-links`.
- Reports, Users, Enrollments, Audit trail; ikut tapisan semasa. Formula injection dineutralkan.
- PDF: guna print browser (laporan & sijil).

### UR-24 System Administration (Ada)
- Users (`/users`): tambah, edit, carian, tapis, aktif/nyahaktif, reset password.
- Departments (`/departments`): tambah, tukar nama (ikut sekali pada pengguna & kursus), buang jika kosong.
- Settings (`/settings`): nama organisasi, markah lulus default, prefix nombor sijil.
- Urus kursus dan pendaftaran.

### UR-25 Security & Backup (Ada)
- CSRF, password hash, middleware role, throttle login, akaun nonaktif disekat.
- Polisi password: min 8, huruf besar + kecil, nombor (`Password::defaults()` dalam `AppServiceProvider`), hint pada semua form password.
- Backup: `php artisan backup:run` = mysqldump + fail upload (`storage/app/private`, `public`) dalam zip di `storage/app/backups`, simpan 14 terbaru (`config/backup.php`). Dijadualkan 01:00 setiap hari (`routes/console.php`).
- Settings: senarai backup terkini, amaran jika tiada backup 36 jam, butang "Back up now". Fail tak boleh dimuat turun dari web.

## Keputusan

1. **UR-01 Login:** ID staf atau email dalam satu field. Register awam ditutup, admin cipta akaun. (2026-09-28)
2. **UR-07 Kelulusan:** admin sahaja, tiada role baru. (2026-09-28)
3. **UR-12/17 Bersemuka:** campur online + bersemuka, perlu sesi, kalendar, kehadiran. (2026-09-28)
4. **UR-05 Nyahaktif:** pilihan A, Inactive = unpublish, tiada schema baru. (2026-09-28)
5. **UR-23 Export:** CSV + `.xlsx`. PDF guna print browser. (2026-10-01)
6. **UR-25 Backup:** dalam app, scheduled `mysqldump`. Polisi password min 8 + huruf besar/kecil + nombor. (2026-10-01)
7. **UR-16 Email:** hold, buat paling akhir. (2026-10-01)

## Log

### 2026-09-28
- Audit awal status UR-01 hingga UR-25.
- Keputusan 1-3 dijawab.
- **Fasa 1 siap** (UR-01, 02, 03, 24):
  - Migration `2026_09_28_000001`: `users.staff_id/position/phone/is_active`, table `departments`.
  - `UserController`, `DepartmentController`, `EnsureActive`, halaman profil baru, register dibuang.
  - `Course::DEPARTMENTS` diganti `Department::names()`.
  - Akaun demo MER0001-MER0008, password `password`.
  - Test `UserManagementTest`.
- **Fasa 2 siap** (UR-05, 08, 11, 13, 21, 24):
  - Migration `2026_09_28_000002`: `courses.pass_mark`, `lesson_files`, `settings`.
  - Migration `2026_09_28_000003`: backfill `enrollments.completed_at`.
  - `LessonFile`, `Setting`, `SettingController`, `/history`, `users.show`, carian Enrollments.
  - Bug dibetulkan: `enrollments.completed_at` tak pernah diisi (kini diisi dalam `LearnController::progress`).
  - Test `LearningContentTest`. Jumlah 22/22 lulus.
- **Fasa 3 siap** (UR-07, 12, 17, 18):
  - Migration `2026_09_28_000004`: `courses.requires_approval`, `enrollment_requests`, `trainers`, `training_sessions`, `session_attendees`.
  - `EnrollmentRequestController` (`/requests`), `TrainerController` (`/trainers`), `TrainingSessionController` (`/calendar`, `/sessions`).
  - Komponen `session-history`, `course-sessions`. Seeder demo `TrainingSeeder` (2 trainer, 3 sesi).
  - Test `FaceToFaceTest`. Jumlah 25/25 lulus.
- UI: scrollbar sidebar ikut tema gelap (`.scroll-ink`), jarak menu dirapatkan.

### 2026-10-01
- Semakan: DB bersih (tiada migration pending, semua user ada `staff_id`, jabatan konsisten, semua lesson ada modul). Semua halaman GET dirender untuk 3 role: tiada 500.
- Bug dibetulkan: `/courses/{id}` 500 (view `courses.show` tak wujud, route tak digunakan) - route `show` dibuang.
- **Fasa 4 siap** (UR-16, 19):
  - Migration `2026_10_01_000001`: `notifications`, `course_feedback`.
  - `LmsNotice`, `NotificationController`, `CourseFeedback`, `LearnController::feedback`.
  - Test `EngagementTest`. Jumlah 28/28 lulus.
- **Fasa 5 siap** (UR-22, 23, 25):
  - Migration `2026_10_01_000002`: `audit_logs`. Package baru `phpoffice/phpspreadsheet` ^5.10.
  - `AuditLog`, trait `Auditable`, `AuditLogController` (`/audit`), `Export`, `BackupRun`, export Users/Enrollments.
  - Self-enrol kini guna `Enrollment::firstOrCreate` (supaya diaudit).
  - Backup sebenar diuji: 27 table, zip OK.
  - Test `ComplianceTest`. Jumlah 31/31 lulus.
- Nota: post-update script `boost:update` dalam `composer.json` gagal (package boost tiada). Dah wujud sebelum ni.
- Timezone `config/app.php` ditukar ke `env('APP_TIMEZONE', 'Asia/Kuala_Lumpur')`. Cap masa yang direkod sebelum ni (UTC) akan nampak 8 jam awal.
