Files
prn2026/docs/progress-log.md
2026-06-03 08:51:22 +08:00

1257 lines
52 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Progress Log
## 2026-05-28 - Phase 0: Project Inspection and Planning
Status: Completed
Completed:
- Inspected workspace.
- Confirmed workspace is currently empty.
- Confirmed no git repository is initialized.
- Confirmed no existing Laravel application is present.
- Confirmed no `AGENTS.md` project instruction file is present.
- Checked local tooling:
- PHP 8.5.1 available.
- Composer 2.9.4 available.
- Node 25.1.0 available.
- `npm.cmd` 11.14.1 available.
- `npm` PowerShell shim blocked by execution policy.
- MySQL CLI not available in PATH.
- Created Phase 0 planning documentation.
Changed files:
- `docs/00-project-brief.md`
- `docs/01-development-plan.md`
- `docs/02-architecture.md`
- `docs/03-database-design.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/06-ui-ux-plan.md`
- `docs/07-testing-plan.md`
- `docs/08-deployment-notes.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Pending items:
- Initialize or create Laravel project in Phase 1.
- Confirm exact Laravel version during install.
- Confirm MySQL server credentials and connectivity.
- Verify package compatibility during Composer/npm installation.
- Initialize git repository if desired.
Next step:
- Proceed to Phase 1 only after approval: Laravel setup, authentication scaffolding, Bootstrap 5 base layout, roles, permissions, and base dashboards.
Manual testing for this phase:
- Review documentation files for completeness.
- Confirm assumptions in `docs/decision-log.md`.
## 2026-05-28 - Phase 0 Review Before Implementation
Status: Completed
Completed:
- Reviewed all Phase 0 documentation files against the original requirement.
- Confirmed the required documentation set is present.
- Clarified Phase 1 package baseline in the development plan.
- Clarified `election_settings.is_registration_open` in database and workflow design.
- Recorded optional Telescope and DOMPDF decisions.
Changed files:
- `docs/01-development-plan.md`
- `docs/03-database-design.md`
- `docs/05-workflow-design.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
Pending items:
- Proceed with Phase 1 implementation.
Next step:
- Scaffold Laravel, install packages, configure authentication, Bootstrap layout, roles/permissions, and base dashboards.
## 2026-05-28 - Phase 1: Laravel Setup and Authentication
Status: Completed
Completed:
- Scaffolded Laravel application.
- Installed Laravel framework 13.12.0.
- Installed Laravel Breeze authentication scaffolding.
- Disabled generic public account registration route.
- Installed and configured Bootstrap 5 layout through Vite.
- Installed Bootstrap Icons, jQuery, SweetAlert2, Tom Select, Flatpickr, and DataTables Bootstrap packages.
- Installed `spatie/laravel-permission` and published migrations/config.
- Installed `spatie/laravel-activitylog` and published migrations/config.
- Installed `simplesoftwareio/simple-qrcode`.
- Attempted `maatwebsite/excel`; Composer rejected it for PHP 8.5.1/Laravel 13 compatibility.
- Installed `openspout/openspout` as compatible spreadsheet export foundation.
- Installed Larastan/PHPStan.
- Added role middleware aliases.
- Added User `HasRoles` support.
- Added role and permission seeder.
- Added default Admin seeding through `config/prn.php`.
- Added role-based dashboard routes and base dashboard UI.
- Updated auth/profile/welcome views to Bootstrap.
- Updated `.env.example` for MySQL.
- Set application timezone to `Asia/Kuala_Lumpur`.
- Kept local `.env` on SQLite because MySQL server credentials are not yet available.
- Added tests for disabled registration and dashboard role protection.
Changed files:
- Laravel application scaffold files.
- `app/Http/Controllers/DashboardController.php`
- `app/Models/User.php`
- `bootstrap/app.php`
- `config/activitylog.php`
- `config/permission.php`
- `config/prn.php`
- `config/app.php`
- `database/migrations/*permission*`
- `database/migrations/*activity_log*`
- `database/seeders/DatabaseSeeder.php`
- `database/seeders/RolePermissionSeeder.php`
- `resources/css/app.css`
- `resources/js/app.js`
- `resources/views/auth/*.blade.php`
- `resources/views/dashboards/index.blade.php`
- `resources/views/layouts/*.blade.php`
- `resources/views/profile/edit.blade.php`
- `resources/views/welcome.blade.php`
- `routes/auth.php`
- `routes/web.php`
- `tests/Feature/Auth/RegistrationTest.php`
- `tests/Feature/DashboardAccessTest.php`
- `.env.example`
- `.gitignore`
- `composer.json`
- `composer.lock`
- `package.json`
- `package-lock.json`
- `phpstan.neon`
- `docs/*`
Verification:
- `php artisan migrate --seed` completed after seeder correction.
- `php artisan db:seed` completed.
- `npm.cmd run build` passed.
- `php artisan route:list` passed.
- `php artisan test` passed: 27 tests, 64 assertions.
- `vendor\bin\pint.bat --test` passed.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
Pending items:
- Confirm MySQL database credentials and switch local `.env` to MySQL when available.
- Implement Phase 2 core domain migrations/models/seeders.
- Replace OpenSpout with `maatwebsite/excel` only if a compatible release becomes available or runtime PHP target changes.
Manual testing:
- Visit `/`.
- Log in as seeded Admin:
- email: `admin@prn.local`
- password: `password`
- Confirm `/dashboard` redirects Admin to `/admin/dashboard`.
- Confirm `/register` is not available.
- Resize browser to confirm mobile navbar behavior.
Next step:
- Phase 2: Core database and seeders for election hierarchy, positions, quotas, applications, assignments, and operational records.
## 2026-05-28 - Phase 2: Core Database and Seeders
Status: Completed
Completed:
- Added core election-domain migration.
- Added `user_profiles`, election hierarchy, position/quota, application/document/history, assignment/history, representative, wheelchair, attendance, finance, export, and note tables.
- Added domain models and Eloquent relationships.
- Added baseline factories for election hierarchy, positions, applications, and assignments.
- Added `PositionSeeder`.
- Added `SampleElectionSeeder`.
- Updated `DatabaseSeeder` to seed roles, positions, Admin user, and sample election data.
- Seeded sample election `PRN2026`.
- Seeded one Bahagian Pilihanraya, one Daerah Mengundi, one Pusat Mengundi, and three Saluran Mengundi.
- Seeded 9 default positions and 17 sample quotas.
- Seeded sample Admin Kewangan, PPM, and KTM users.
- Seeded sample dual-role assignment where one user is both PPM and KTM.
- Seeded sample wheelchair allocation.
- Added feature test for core domain seeder output and dual-role assignment.
- Confirmed MySQL connection through Laravel/PDO.
- Shortened long composite index names for MySQL compatibility.
Changed files:
- `database/migrations/2026_05_28_030000_create_phase2_core_domain_tables.php`
- `app/Models/*.php`
- `database/factories/*.php`
- `database/seeders/DatabaseSeeder.php`
- `database/seeders/PositionSeeder.php`
- `database/seeders/SampleElectionSeeder.php`
- `tests/Feature/CoreDomainSeederTest.php`
- `docs/00-project-brief.md`
- `docs/01-development-plan.md`
- `docs/03-database-design.md`
- `docs/07-testing-plan.md`
- `docs/08-deployment-notes.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan migrate:fresh --seed` passed on MySQL database `prn2026`.
- `php artisan test` passed: 28 tests, 80 assertions.
- `vendor\bin\pint.bat --test` passed.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
Manual testing:
- Log in as `admin@prn.local` / `password`.
- Confirm base dashboard loads after fresh seed.
- Optional sample accounts:
- `kewangan@prn.local` / `password`
- `ppm@prn.local` / `password`
- `ktm@prn.local` / `password`
- Confirm `/dashboard` redirects based on each user's role.
Pending items:
- Phase 3 Admin setup module UI and CRUD.
- Implement policy-level ownership checks when domain UI routes are added.
- Add business-rule services for vacancy and registration period calculations in later phases.
Next step:
- Phase 3: Admin setup module for CRUD Bahagian, Daerah, Pusat, Saluran, Jawatan/quota setup, PPM assignment, and QR generation.
## 2026-05-29 - Phase 3: Admin Setup Module
Status: Completed
Completed:
- Added Admin setup routes under `/admin/setup`.
- Added setup overview page.
- Added CRUD controllers, Form Requests, and Blade views for Bahagian Pilihanraya, Daerah Mengundi, Pusat Mengundi, Saluran Mengundi, Jawatan, and Kekosongan Jawatan.
- Added Pusat Mengundi detail page with saluran list, QR registration link, QR preview, and PPM assignment form.
- Added QR generation service using public UUID registration URLs.
- Added Admin-protected QR SVG serving route.
- Added public QR placeholder route `/pohon/{pusatMengundi:public_uuid}`.
- Added PPM assignment service using `staff_assignments`, assignment history, RBAC role assignment, and activity logging.
- Added quota validation to prevent assigning a Saluran Mengundi from a different Pusat Mengundi.
- Added public Blade layout for QR-facing pages.
- Linked Admin dashboard action to Election setup.
- Added feature tests for Admin setup module behavior.
Changed files:
- `app/Http/Controllers/Admin/Setup/AdminSetupController.php`
- `app/Http/Controllers/Admin/Setup/BahagianPilihanrayaController.php`
- `app/Http/Controllers/Admin/Setup/DaerahMengundiController.php`
- `app/Http/Controllers/Admin/Setup/PositionController.php`
- `app/Http/Controllers/Admin/Setup/PositionQuotaController.php`
- `app/Http/Controllers/Admin/Setup/PusatMengundiController.php`
- `app/Http/Controllers/Admin/Setup/SaluranMengundiController.php`
- `app/Http/Controllers/DashboardController.php`
- `app/Http/Controllers/PublicApplicationPlaceholderController.php`
- `app/Http/Requests/Admin/Setup/*.php`
- `app/Services/Admin/PpmAssignmentService.php`
- `app/Services/Admin/PusatQrCodeService.php`
- `resources/views/admin/setup/**/*.blade.php`
- `resources/views/dashboards/index.blade.php`
- `resources/views/layouts/public.blade.php`
- `resources/views/public/application-placeholder.blade.php`
- `routes/web.php`
- `tests/Feature/AdminSetupTest.php`
- `docs/01-development-plan.md`
- `docs/05-workflow-design.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 65 routes.
- `php artisan test --filter=AdminSetupTest` passed: 4 tests, 24 assertions.
- `php artisan test` passed: 32 tests, 104 assertions.
- `vendor\bin\pint.bat --test` passed.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `admin@prn.local` / `password`.
- Open `/admin/setup`.
- Create or edit Bahagian, Daerah, Pusat, Saluran, Jawatan, and Kuota records.
- Open a Pusat Mengundi detail page, generate QR, and assign PPM.
- Open the generated `/pohon/{uuid}` public link and confirm it shows the intended Pusat Mengundi.
- Log in as `ktm@prn.local` / `password` and confirm `/admin/setup` is forbidden.
Pending items:
- Full public application form and document upload in Phase 4.
- Registration-period enforcement for public and KTM-created applications in Phase 4 and Phase 6.
- Representative management for Police, KKM, and JKM in the later Admin management phase.
- Rich filters for very large setup lists if operational data volume requires them.
Next step:
- Phase 4: Public application module using QR link, registration-period rules, document uploads, KTM selection for KP/KPDP, and duplicate IC blocking.
## 2026-05-29 - Phase 4: Public Application Module
Status: Completed
Completed:
- Replaced QR placeholder flow with public application form on `/pohon/{pusatMengundi:public_uuid}`.
- Added public success page using application public UUID.
- Added `RegistrationPeriodService` for registration open/closed checks.
- Added `KtmVacancyService` for KP/KPDP KTM selection and vacancy calculation.
- Added `PublicApplicationSubmissionService` for transactional application creation, private document storage, status history, bank verification initialization, and activity logging.
- Added `StorePublicApplicationRequest` with validation for applicant fields, IC normalization, required documents, public roles, duplicate IC, KTM-created blocking rule, and KTM vacancy recheck.
- Added responsive public Blade form for applicant details, role selection, KTM selection, bank data, and document upload.
- Added closed-registration page.
- Stored IC document and bank statement metadata in `application_documents`.
- Created pending `bank_verifications` row for public submissions.
- Added Phase 4 feature tests and unit tests.
Changed files:
- `app/Http/Controllers/PublicApplicationController.php`
- `app/Http/Requests/Public/StorePublicApplicationRequest.php`
- `app/Services/RegistrationPeriodService.php`
- `app/Services/Public/KtmVacancyService.php`
- `app/Services/Public/PublicApplicationSubmissionService.php`
- `resources/views/layouts/public.blade.php`
- `resources/views/public/applications/create.blade.php`
- `resources/views/public/applications/closed.blade.php`
- `resources/views/public/applications/success.blade.php`
- `routes/web.php`
- `tests/Feature/PublicApplicationTest.php`
- `tests/Unit/KtmVacancyServiceTest.php`
- `tests/Unit/RegistrationPeriodServiceTest.php`
- `docs/01-development-plan.md`
- `docs/03-database-design.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 67 routes.
- `php artisan test --filter=PublicApplicationTest` passed: 6 tests, 27 assertions.
- `php artisan test` passed: 41 tests, 137 assertions.
- `vendor\bin\pint.bat --test` passed.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `npm.cmd run build` passed.
Manual testing:
- Open a generated `/pohon/{uuid}` QR link.
- Submit a KTM or PAPM application with IC document and bank statement.
- Submit KP with an available KTM selection.
- Try submitting without IC document or bank statement and confirm validation blocks it.
- Set registration end date to a past date and confirm public form shows closed-registration message.
- Create a `created_by_ktm` application for an IC and confirm public self-registration with the same IC is blocked.
Pending items:
- Phase 5 PPM review, approval/rejection, role change, and assignment of submitted public applications.
- Phase 6 KTM-created application deletion flow and email notification.
- Authorized document viewing/downloading for PPM/Admin/Admin Kewangan.
- Public application status portal if later required.
Next step:
- Phase 5: PPM review and assignment module.
## 2026-05-29 - Phase 5: PPM Review and Assignment Module
Status: Completed
Completed:
- Added PPM application review routes under `/ppm/applications`.
- Added PPM-scoped application list and detail screens.
- Added `ApplicationPolicy` and `PpmScopeService` for record-level PPM access control.
- Added `PpmApplicationReviewService` for transactional approve/reject behavior.
- Added `AssignmentVacancyService` for Pusat/Saluran quota checks.
- Extended `KtmVacancyService` to ignore the current application during PPM approval vacancy checks.
- Added PPM approval form allowing role change before approval.
- Implemented KTM assignment to available Saluran Mengundi.
- Implemented KP/KPDP assignment to active KTM with remaining vacancy.
- Implemented PAPM assignment at Pusat Mengundi level.
- Implemented rejection with required reason.
- Added authorized private document download for PPM-owned applications.
- Added PPM dashboard metrics and link to the review queue.
- Added representative display sections for Police, KKM, and JKM records.
- Added `AuthorizesRequests` to the base controller for policy authorization.
- Added Phase 5 feature tests.
Changed files:
- `app/Http/Controllers/Controller.php`
- `app/Http/Controllers/DashboardController.php`
- `app/Http/Controllers/Ppm/ApplicationReviewController.php`
- `app/Http/Requests/Ppm/ApproveApplicationRequest.php`
- `app/Http/Requests/Ppm/RejectApplicationRequest.php`
- `app/Models/PusatMengundi.php`
- `app/Policies/ApplicationPolicy.php`
- `app/Services/Ppm/AssignmentVacancyService.php`
- `app/Services/Ppm/PpmApplicationReviewService.php`
- `app/Services/Ppm/PpmScopeService.php`
- `app/Services/Public/KtmVacancyService.php`
- `resources/views/ppm/applications/index.blade.php`
- `resources/views/ppm/applications/show.blade.php`
- `routes/web.php`
- `tests/Feature/PpmApplicationReviewTest.php`
- `docs/01-development-plan.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 72 routes.
- `php artisan test --filter=PpmApplicationReviewTest` passed: 6 tests, 24 assertions.
- `php artisan test` passed: 47 tests, 161 assertions.
- `vendor\bin\pint.bat --test` passed.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `ppm@prn.local` / `password`.
- Open `/ppm/applications`.
- Submit a public application through QR first, then confirm it appears in the PPM queue.
- Open the application detail page and download uploaded documents.
- Approve a KTM application into an available Saluran.
- Approve a KP/KPDP application under an active KTM.
- Change an applicant role before approval and confirm assignment is created.
- Reject an application with a reason.
- Confirm a PPM cannot access an application outside their assigned Pusat Mengundi.
Pending items:
- Phase 6 KTM flow for KP registration/approval, deletion of KTM-created records, and email notification.
- Admin/Admin Kewangan document viewing routes.
- Admin global management and post-registration notes in Phase 7.
- Attendance module in Phase 10.
Next step:
- Phase 6: KTM flow for assigned Saluran, KP registration, KP approval, KTM-created deletion, and email notification.
## 2026-05-29 - Phase 6: KTM Flow
Status: Completed
Completed:
- Added KTM application routes under `/ktm/applications`.
- Added `KtmScopeService` for active KTM assignment ownership checks.
- Added `KtmApplicationService` for KTM KP registration, KP approval, and KTM-created deletion.
- Added queued Markdown Mailable `KtmCreatedApplicantMail`.
- Added KTM team list showing assigned Saluran, active KP team members, and KP vacancy.
- Added KTM KP registration form.
- Added KTM application detail page with approve/delete actions.
- Enforced KTM registration period on KP registration and approval.
- Enforced KP-only creation and approval for KTM.
- Enforced own-team-only approval/deletion.
- Implemented `source = created_by_ktm` for KTM-created records.
- Implemented delete flow that sets `deleted_by_ktm`, records status history, and soft deletes the KTM-created application.
- Updated KTM dashboard with live metrics and navigation links.
- Added Phase 6 feature tests.
Changed files:
- `app/Http/Controllers/DashboardController.php`
- `app/Http/Controllers/Ktm/TeamController.php`
- `app/Http/Requests/Ktm/RegisterKpApplicantRequest.php`
- `app/Mail/KtmCreatedApplicantMail.php`
- `app/Services/Ktm/KtmApplicationService.php`
- `app/Services/Ktm/KtmScopeService.php`
- `app/Services/Public/KtmVacancyService.php`
- `resources/views/emails/ktm/created-applicant.blade.php`
- `resources/views/ktm/applications/create.blade.php`
- `resources/views/ktm/applications/index.blade.php`
- `resources/views/ktm/applications/show.blade.php`
- `routes/web.php`
- `tests/Feature/KtmFlowTest.php`
- `docs/01-development-plan.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 78 routes.
- `php artisan test --filter=KtmFlowTest` passed: 6 tests, 25 assertions.
- `php artisan test` passed: 53 tests, 186 assertions.
- `vendor\bin\pint.bat --test` passed.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `ktm@prn.local` / `password`.
- Open `/ktm/applications`.
- Confirm assigned Saluran and KP vacancy are shown.
- Register a KP and confirm email is queued/sent according to local mail configuration.
- Approve a KP under own team and confirm active assignment is created.
- Try approving KP from another KTM team and confirm it is blocked.
- Try approving a non-KP application and confirm it is blocked.
- Set registration end date to the past and confirm KTM registration/approval is blocked.
- Delete an unassigned KTM-created applicant and confirm public self-registration with the same IC is no longer blocked.
Pending items:
- Phase 7 Admin global management/manual entry and post-registration notes.
- Admin/Admin Kewangan document viewing routes.
- Finance verification module in Phase 8.
- Attendance module in Phase 10.
Next step:
- Phase 7: Admin management and manual entry.
## 2026-05-29 - Phase 7: Admin Management and Manual Entry
Status: Completed
Completed:
- Added Admin management routes under `/admin/management`.
- Added Admin management overview dashboard.
- Added global application list with filters.
- Added Admin manual application entry with `source = admin_manual`.
- Added Admin application edit screen.
- Added direct assignment from Admin application edit screen.
- Added global staff assignment list and assignment edit screen.
- Added post-registration catatan enforcement through `AdminPostCloseNoteService`.
- Added `system_notes` records for accepted post-closing Admin changes.
- Added assignment/application history and activity log entries for Admin changes.
- Added Police, KKM, and JKM representative entry/deletion screen.
- Updated Admin dashboard with live counts and management module links.
- Added Phase 7 feature tests.
Changed files:
- `app/Http/Controllers/Admin/Management/AdminManagementController.php`
- `app/Http/Controllers/Admin/Management/ManagedApplicationController.php`
- `app/Http/Controllers/Admin/Management/RepresentativeController.php`
- `app/Http/Controllers/Admin/Management/StaffAssignmentController.php`
- `app/Http/Controllers/DashboardController.php`
- `app/Http/Requests/Admin/Management/*.php`
- `app/Services/Admin/Management/*.php`
- `resources/views/admin/management/**/*.blade.php`
- `routes/web.php`
- `tests/Feature/AdminManagementTest.php`
- `docs/01-development-plan.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 91 routes.
- `php artisan test --filter=AdminManagementTest` passed: 5 tests, 18 assertions.
- `php artisan test` passed: 58 tests, 204 assertions.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `vendor\bin\pint.bat --test` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `admin@prn.local` / `password`.
- Open `/admin/management`.
- Create a manual application.
- Edit a manual or public application.
- Direct assign an application to a Pusat, Saluran, or KTM team.
- Edit an existing staff assignment.
- Create Police, KKM, and JKM representative records.
- Close the registration period for the election and confirm Admin changes require catatan.
- Log in as `kewangan@prn.local` / `password` and confirm `/admin/management/assignments` is forbidden.
Pending items:
- Admin document viewing route for IC/bank statement remains for the finance/document module.
- Excel export implementation remains in later finance/export phases.
- More granular representative edit forms can be added if operational users need inline correction instead of delete/recreate.
Next step:
- Phase 8: Admin Kewangan module for bank verification, finance filters, and finance export.
## 2026-05-29 - Phase 8: Admin Kewangan
Status: Completed
Completed:
- Added finance bank verification routes under `/kewangan/bank`.
- Added Admin Kewangan list of approved/assigned staff bank records.
- Added filters for status, Pusat Mengundi, role, missing bank statement, missing account number, and keyword.
- Added bank verification detail screen.
- Added finance status update with finance note, verified by, and verified at.
- Added activity log for finance verification changes.
- Added sensitive display masking helper.
- Added finance XLSX export using OpenSpout.
- Added export log creation for finance exports.
- Updated Admin Kewangan dashboard with live counts and module links.
- Added Phase 8 feature tests.
Changed files:
- `app/Exports/FinanceVerificationExport.php`
- `app/Http/Controllers/DashboardController.php`
- `app/Http/Controllers/Kewangan/BankVerificationController.php`
- `app/Http/Requests/Kewangan/UpdateBankVerificationRequest.php`
- `app/Services/Finance/BankVerificationService.php`
- `app/Services/Finance/FinanceExportService.php`
- `app/Services/Finance/FinanceVerificationQuery.php`
- `app/Support/SensitiveData.php`
- `resources/views/kewangan/bank/index.blade.php`
- `resources/views/kewangan/bank/show.blade.php`
- `routes/web.php`
- `tests/Feature/FinanceModuleTest.php`
- `docs/01-development-plan.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 95 routes.
- `php artisan test --filter=FinanceModuleTest` passed: 5 tests, 18 assertions.
- `php artisan test` passed: 63 tests, 222 assertions.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `vendor\bin\pint.bat --test` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `kewangan@prn.local` / `password`.
- Open `/kewangan/bank`.
- Filter records by Pusat, role, status, missing bank statement, and missing account number.
- Open a bank verification record.
- Mark it verified, rejected, or requires correction with a finance note.
- Export the finance list and confirm a file downloads.
- Confirm `/admin/management/assignments` is forbidden for Admin Kewangan.
Pending items:
- Admin/Admin Kewangan authorized document download for bank statement remains to be added when document review UX is finalized.
- Additional finance export formats can be added if official template is provided.
Next step:
- Phase 9: Wheelchair management.
## 2026-05-29 - Phase 9: Wheelchair Management
Status: Completed
Completed:
- Added Admin wheelchair management routes under `/admin/management/wheelchairs`.
- Added allocation upsert per election and Pusat Mengundi.
- Added wheelchair management service for allocation and transaction rules.
- Added taken transaction recording with quantity, time, person taking, and notes.
- Added return transaction recording with quantity, time, condition, and notes.
- Added quantity guards for allocation, available balance, and outstanding return balance.
- Added activity logging for allocation and transaction changes.
- Added wheelchair list and detail screens.
- Updated Admin management dashboard and navigation.
- Added Phase 9 feature tests.
Changed files:
- `app/Http/Controllers/Admin/Management/AdminManagementController.php`
- `app/Http/Controllers/Admin/Management/WheelchairController.php`
- `app/Http/Requests/Admin/Management/StoreWheelchairTransactionRequest.php`
- `app/Http/Requests/Admin/Management/UpsertWheelchairAllocationRequest.php`
- `app/Services/Admin/Management/WheelchairManagementService.php`
- `resources/views/admin/management/_nav.blade.php`
- `resources/views/admin/management/index.blade.php`
- `resources/views/admin/management/wheelchairs/index.blade.php`
- `resources/views/admin/management/wheelchairs/show.blade.php`
- `routes/web.php`
- `tests/Feature/WheelchairManagementTest.php`
- `docs/01-development-plan.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 100 routes.
- `php artisan test --filter=WheelchairManagementTest` passed: 6 tests, 16 assertions.
- `php artisan test` passed: 69 tests, 238 assertions.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `vendor\bin\pint.bat --test` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `admin@prn.local` / `password`.
- Open `/admin/management/wheelchairs`.
- Create or update a wheelchair allocation for a Pusat Mengundi.
- Open the allocation detail screen.
- Record wheelchair taken transaction.
- Record wheelchair returned transaction with condition `baik` or `rosak`.
- Try taking more than available and confirm validation blocks it.
- Try returning more than outstanding and confirm validation blocks it.
- Try lowering allocation below outstanding and confirm validation blocks it.
- Log in as `kewangan@prn.local` / `password` and confirm wheelchair management is forbidden.
Pending items:
- Phase 10 attendance module.
- Optional wheelchair export/report if later required.
Next step:
- Phase 10: Attendance module.
## 2026-05-29 - Phase 10: Attendance Module
Status: Completed
Completed:
- Added PPM attendance routes under `/ppm/attendance`.
- Added PPM attendance list for assigned Pusat Mengundi.
- Added PPM attendance recording screen for active staff under own Pusat Mengundi.
- Added attendance activation guard using `election_settings.is_attendance_active`.
- Added bulk attendance recording service.
- Added activity log entries for attendance updates.
- Added Admin attendance routes under `/admin/attendance`.
- Added Admin attendance dashboard by Pusat Mengundi.
- Added Admin attendance detail view with staff, role, Saluran, status, check-in time, notes, and recorded by.
- Added attendance summary service with totals and role-level summary.
- Added attendance detail XLSX export using OpenSpout.
- Added export log creation for attendance exports.
- Updated Admin and PPM dashboard links/metrics.
- Added Phase 10 feature and unit tests.
Changed files:
- `app/Exports/AttendanceDetailExport.php`
- `app/Http/Controllers/Admin/AttendanceController.php`
- `app/Http/Controllers/DashboardController.php`
- `app/Http/Controllers/Ppm/AttendanceController.php`
- `app/Http/Requests/Ppm/RecordAttendanceRequest.php`
- `app/Services/Attendance/AttendanceExportService.php`
- `app/Services/Attendance/AttendanceRecordingService.php`
- `app/Services/Attendance/AttendanceSummaryService.php`
- `resources/views/admin/attendance/index.blade.php`
- `resources/views/admin/attendance/show.blade.php`
- `resources/views/ppm/attendance/index.blade.php`
- `resources/views/ppm/attendance/show.blade.php`
- `routes/web.php`
- `tests/Feature/AttendanceModuleTest.php`
- `tests/Unit/AttendanceSummaryServiceTest.php`
- `docs/01-development-plan.md`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/07-testing-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan route:list --except-vendor` passed and shows 106 routes.
- `php artisan test --filter=Attendance` passed: 7 tests, 21 assertions.
- `php artisan test` passed: 76 tests, 259 assertions.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `vendor\bin\pint.bat --test` passed.
- `npm.cmd run build` passed.
Manual testing:
- Activate attendance for the election in database/settings.
- Log in as `ppm@prn.local` / `password`.
- Open `/ppm/attendance`.
- Record present/absent/not recorded statuses for staff under own Pusat Mengundi.
- Confirm PPM cannot access or record another Pusat Mengundi.
- Log in as `admin@prn.local` / `password`.
- Open `/admin/attendance`.
- View Pusat Mengundi summary and detail.
- Export attendance detail and confirm file downloads.
- Log in as `kewangan@prn.local` / `password` and confirm Admin attendance dashboard is forbidden.
Pending items:
- Admin settings UI to toggle `is_attendance_active` if operational users need UI control.
- Official attendance report template can replace the current export layout when provided.
Next step:
- Phase 11: Testing, polish, security review, performance review, and final hardening.
## 2026-05-29 - Phase 11: Testing, Polish, and Hardening
Status: Completed
Completed:
- Reviewed authorization, private document access, sensitive data masking, exports, and quality gates.
- Added Admin document download route for private application documents.
- Added Admin Kewangan bank statement download route.
- Restricted finance document downloads to `bank_statement` only.
- Added activity logging for Admin and finance document downloads.
- Added secure document links to Admin application edit and finance bank detail screens.
- Added feature tests for Admin/Admin Kewangan/unauthorized document access.
- Added unit test for sensitive data masking.
- Updated deployment notes with final quality gate commands and document storage hardening notes.
- Updated Phase 11 documentation and release notes.
Changed files:
- `app/Http/Controllers/DocumentDownloadController.php`
- `app/Http/Controllers/Admin/Management/ManagedApplicationController.php`
- `resources/views/admin/management/applications/edit.blade.php`
- `resources/views/kewangan/bank/show.blade.php`
- `routes/web.php`
- `tests/Feature/DocumentDownloadAuthorizationTest.php`
- `tests/Unit/SensitiveDataTest.php`
- `docs/01-development-plan.md`
- `docs/07-testing-plan.md`
- `docs/08-deployment-notes.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Verification:
- `php artisan test --filter=DocumentDownloadAuthorizationTest` passed: 3 tests, 4 assertions.
- `php artisan test --filter=SensitiveDataTest` passed: 1 test, 4 assertions.
- `php artisan route:list --except-vendor` passed and shows 108 routes.
- `php artisan test` passed: 80 tests, 267 assertions.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` passed.
- `vendor\bin\pint.bat --test` passed.
- `npm.cmd run build` passed.
Manual testing:
- Log in as `admin@prn.local` / `password`.
- Open an application with uploaded documents and download IC/bank documents.
- Log in as `kewangan@prn.local` / `password`.
- Open bank verification detail and download bank statement.
- Confirm Admin Kewangan cannot download IC document through finance document route.
- Run end-to-end smoke test from QR application to attendance export.
Pending items:
- Replace current exports with official report templates if/when provided.
- Add Admin UI toggle for attendance activation if operational users need it outside database/settings maintenance.
Next step:
- Production readiness review with real environment credentials, mail transport, queue worker, HTTPS, backup plan, and user acceptance testing.
## 2026-05-31 - Penambahbaikan daftar Pusat Mengundi
### Selesai
- Membuang keperluan nama Saluran daripada borang dan validasi setup Saluran.
- Menambah sepuluh input bilangan operasi pada borang daftar Pusat Mengundi.
- Menjana Saluran bernombor serta kuota Pusat dan Saluran secara automatik semasa daftar Pusat.
- Menukar istilah Calon Simpanan kepada Calon Tambahan dengan migrasi data.
- Menambah ujian ciri untuk penciptaan Pusat, Saluran tanpa nama dan kuota operasi.
### Fail berubah
- `app/Services/Admin/PusatOperationalSetupService.php`
- `app/Http/Controllers/Admin/Setup/PusatMengundiController.php`
- `app/Http/Requests/Admin/Setup/UpsertPusatMengundiRequest.php`
- `app/Http/Requests/Admin/Setup/UpsertSaluranMengundiRequest.php`
- `resources/views/admin/setup/pusat/_form.blade.php`
- `resources/views/admin/setup/saluran/_form.blade.php`
- `database/migrations/2026_05_31_000000_rename_calon_simpanan_position_to_calon_tambahan.php`
- `database/seeders/PositionSeeder.php`
- `database/seeders/SampleElectionSeeder.php`
- `tests/Feature/Admin/PusatOperationalSetupTest.php`
### Semakan manual
- Buka `/admin/setup/pusat/create`, pastikan sepuluh medan bilangan operasi dipaparkan.
- Daftar Pusat baharu dan pastikan Saluran bernombor dijana tanpa meminta nama Saluran.
### Seterusnya
- Jalankan migrasi, ujian automatik dan semakan statik selepas shell runner tersedia.
## 2026-06-02 - Perancangan Fasa 1215: Pembetulan dan Penambahbaikan
Status: Selesai (perancangan)
Selesai:
- Menjalankan semakan kod menyeluruh ke atas keseluruhan sistem selepas Phase 11 dan penambahbaikan 2026-05-31.
- Mengenal pasti lapan isu meliputi keselamatan, prestasi, pengalaman pengguna, dan pengurusan data.
- Menyusun isu-isu tersebut kepada empat fasa penambahbaikan berprioritikan (Fasa 1215).
- Mendokumentasikan plan penuh dalam `docs/09-improvement-plan.md`.
- Mengemas kini `docs/01-development-plan.md` dengan ringkasan Fasa 1215.
Fail berubah:
- `docs/09-improvement-plan.md` (baharu)
- `docs/01-development-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Isu yang dikenal pasti:
- 12-A: Tiada UI toggle untuk `is_attendance_active` dan `is_registration_open_override` — memerlukan edit database terus dalam produksi.
- 12-B: Semakan IC duplikasi mungkin tidak mengecualikan soft-deleted records secara eksplisit dan konsisten.
- 12-C: `AdminPostCloseNoteService` boleh dipintas jika controller baharu lupa memanggilnya.
- 12-D: `SampleElectionSeeder` mungkin masih mengandungi rujukan kepada `CALON_SIMPANAN` selepas migration rename Phase 11.
- 12-E: Semakan jenis dokumen pada path download tidak sepenuhnya konsisten antara peranan.
- 13-A: Composite indexes belum wujud pada `applications`, `staff_assignments`, `bank_verifications` — boleh perlahan apabila data besar.
- 14-A: Tiada halaman status permohonan untuk pemohon awam — mereka perlu hubungi Admin untuk semak status.
- 15-A: Fail XLSX eksport sensitif disimpan tanpa had masa — polisi purge automatik diperlukan.
Seterusnya:
- Mulakan Fasa 12 dengan 12-A (Admin Settings UI) kerana ia paling mendesak untuk kebolehgunaan dalam persekitaran produksi.
## 2026-06-02 - Fasa 12-A: Admin Settings UI dan 12-D: Pembetulan Seeder
Status: Selesai
Selesai:
- Tambah halaman Admin Settings di `/admin/setup/settings/{election}` untuk toggle `is_attendance_active` dan `is_registration_open_override` tanpa perlu edit database.
- Tambah `ElectionSettingsController`, `ElectionSettingsService`, `UpdateElectionSettingsRequest`.
- Tambah view `admin/setup/settings/edit.blade.php` dengan toggle radio untuk kedua-dua tetapan, badge status semasa, dan amaran override aktif.
- Tambah pautan "Tetapan" (kuning) ke `admin/setup/_nav.blade.php` dan setup index actions.
- Perubahan tetapan direkod dalam `activity_log` dengan nilai sebelum dan selepas.
- Betulkan bug 12-D: `SampleElectionSeeder::seedQuotas()` masih query `CALON_SIMPANAN` — ditukar kepada `CALON_TAMBAHAN`.
- Betulkan `AdminSetupTest`: tambah medan operasi yang diperlukan untuk pusat.store, dan tukar nombor saluran dari '1' ke '3' untuk elak konflik dengan saluran auto-jana.
- Betulkan anotasi PHPDoc pada `UpdateElectionSettingsRequest::prepareForValidation()`.
- Tambah anotasi `@var ElectionSetting` pada `ElectionSettingsService` untuk PHPStan.
- Jalankan `pint` (auto-fix 2 fail) dan `phpstan` (0 error).
Fail berubah:
- `app/Http/Controllers/Admin/Setup/ElectionSettingsController.php` (baharu)
- `app/Http/Requests/Admin/Setup/UpdateElectionSettingsRequest.php` (baharu)
- `app/Services/Admin/ElectionSettingsService.php` (baharu)
- `resources/views/admin/setup/settings/edit.blade.php` (baharu)
- `resources/views/admin/setup/_nav.blade.php`
- `resources/views/admin/setup/index.blade.php`
- `routes/web.php`
- `database/seeders/SampleElectionSeeder.php`
- `tests/Feature/Admin/ElectionSettingsTest.php` (baharu)
- `tests/Feature/AdminSetupTest.php`
- `docs/04-rbac-permission-matrix.md`
- `docs/05-workflow-design.md`
- `docs/09-improvement-plan.md`
- `docs/decision-log.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan route:list --except-vendor` — 110 routes (tambah 2).
- `php artisan test` — 90 tests, 310 assertions (**selesai, semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Seterusnya:
- 12-B: Semak dan betulkan query IC duplikasi untuk pastikan soft-deleted records dikecualikan.
- 12-C: Perkukuh enforcement nota catatan post-pendaftaran.
- 12-E: Konsistensikan semakan jenis dokumen download.
## 2026-06-02 - Fasa 12-B: Pembetulan Semakan IC Soft-Deleted
Status: Selesai
Selesai:
- Audit menyeluruh semua lokasi semakan IC duplikasi: `StorePublicApplicationRequest::validateDuplicateIc()`, `KtmApplicationService::registerKp()`, `KtmVacancyService::remainingVacancy()`, dan `AssignmentVacancyService`.
- Disahkan bahawa kedua-dua query IC menggunakan SoftDeletes scope (mengecualikan `deleted_at IS NOT NULL`) DAN `whereNotIn('status', ['cancelled', 'deleted_by_ktm'])` — perlindungan dua lapis yang betul.
- `cancelled` records: dikecualikan oleh `whereNotIn` sahaja (bukan soft-deleted).
- `deleted_by_ktm` records: dikecualikan oleh kedua-dua SoftDeletes scope DAN `whereNotIn` (redundant safety layer).
- Tambah comment eksplisit pada kedua-dua query IC untuk mendokumentasikan intent perlindungan dua lapis ini.
- Tambah 2 ujian baharu dalam `PublicApplicationTest`:
- `test_public_registration_is_unblocked_after_ktm_deletes_applicant`: KTM cipta rekod, KTM delete (soft-delete + status deleted_by_ktm), pemohon awam dengan IC yang sama boleh daftar semula.
- `test_cancelled_application_does_not_block_new_registration`: Rekod `cancelled` (bukan soft-deleted) tidak menyekat pendaftaran IC yang sama.
- `KtmVacancyService` dan `AssignmentVacancyService` disahkan betul — menggunakan whitelist status dan `StaffAssignment` queries tidak melibatkan soft-deleted `Application` records secara salah.
Fail berubah:
- `app/Http/Requests/Public/StorePublicApplicationRequest.php` — tambah comment
- `app/Services/Ktm/KtmApplicationService.php` — tambah comment
- `tests/Feature/PublicApplicationTest.php` — tambah 2 ujian
- `docs/09-improvement-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan test` — 92 tests, 316 assertions (**semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Seterusnya:
- 12-C: Perkukuh enforcement nota catatan post-pendaftaran.
- 12-E: Konsistensikan semakan jenis dokumen download.
## 2026-06-02 - Fasa 12-C: Perkukuh Enforcement Nota Catatan Post-Pendaftaran
Status: Selesai
Selesai:
- Audit semua 6 service methods yang mengubah rekod domain selepas pendaftaran tutup — kesemua sudah memanggil `AdminPostCloseNoteService::requireIfClosed()` dengan betul.
- Masalah: enforcement bergantung pada konvensyen — controller baharu boleh lupa panggil service tersebut.
- Tambah middleware `RequireAdminPostCloseNote` sebagai safety net automatik pada route group `admin/management`.
- Middleware menyemak `election_id` dari request body (untuk create routes) atau active election (untuk edit/delete routes). Jika pendaftaran ditutup dan `note` kosong, redirect balik dengan ralat validasi.
- Daftarkan alias `admin.post_close_note` dalam `bootstrap/app.php`.
- Apply middleware ke `['auth', 'role:Admin', 'admin.post_close_note']` dalam `routes/web.php`.
- Tambah 5 ujian baharu dalam `AdminManagementTest`:
- `test_admin_create_application_after_registration_closed_requires_catatan`
- `test_admin_update_assignment_after_registration_closed_requires_catatan`
- `test_admin_create_representative_after_registration_closed_requires_catatan`
- `test_admin_delete_representative_after_registration_closed_requires_catatan`
- `test_middleware_does_not_block_when_registration_is_open`
Fail berubah:
- `app/Http/Middleware/RequireAdminPostCloseNote.php` (baharu)
- `bootstrap/app.php` — alias middleware baharu
- `routes/web.php` — middleware pada route group management
- `tests/Feature/AdminManagementTest.php` — tambah 5 ujian
- `docs/decision-log.md`
- `docs/09-improvement-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan test` — 97 tests, 337 assertions (**semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Seterusnya:
- 12-E: Konsistensikan semakan jenis dokumen download.
## 2026-06-02 - Fasa 13-A: Composite Indexes Pangkalan Data
Status: Selesai
Selesai:
- Audit index sedia ada berbanding query kritikal dalam `KtmVacancyService`, `AssignmentVacancyService`, `ManagedApplicationController`, dan `DashboardController`.
- Dapatan: dua index yang disenaraikan dalam plan sudah wujud — `(election_id, ic_number)` dan `(election_id, pusat_mengundi_id, status)` pada `applications`, serta dua index komposit pada `staff_assignments`.
- `bank_verifications` tiada kolum `election_id` — index `(election_id, status)` yang diancangkan dalam plan tidak relevan dan tidak ditambah.
- Tiga index baharu yang benar-benar diperlukan ditambah melalui migration `2026_06_02_000000_add_performance_indexes.php`:
- `applications.app_election_status_idx``(election_id, status)` untuk dashboard count queries
- `applications.app_ktm_position_idx``(selected_ktm_assignment_id, requested_position_id)` untuk `KtmVacancyService` reserved count
- `staff_assignments.sa_reports_to_pos_status_idx``(reports_to_assignment_id, position_id, status)` untuk `KtmVacancyService` assigned count
- Dokumentasi index lengkap ditambah dalam `docs/03-database-design.md`.
- Arahan verifikasi index dengan `SHOW INDEX` dan `EXPLAIN` ditambah dalam `docs/08-deployment-notes.md`.
Fail berubah:
- `database/migrations/2026_06_02_000000_add_performance_indexes.php` (baharu)
- `docs/03-database-design.md`
- `docs/08-deployment-notes.md`
- `docs/decision-log.md`
- `docs/09-improvement-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan migrate` — lulus, 2 migration dijalankan.
- `php artisan test` — 97 tests, 337 assertions (**semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Seterusnya:
- 12-E: Konsistensikan semakan jenis dokumen download.
- Fasa 14: Portal status permohonan pemohon awam.
- Fasa 15: Purge automatik fail eksport sensitif.
## 2026-06-02 - Fasa 12-E: Konsistensikan Semakan Jenis Dokumen Download
Status: Selesai
Selesai:
- Audit tiga path download dokumen — PPM, Admin, Finance (Admin Kewangan).
- Dapatan:
- PPM: tiada type check eksplisit, tiada activity log, ownership failure pakai 404 (patut 403).
- Admin: tiada type check eksplisit (senyap allow semua jenis).
- Finance: sudah betul — explicit `bank_statement` check, log activity, pakai 403.
- Tambah `ApplicationDocument::TYPE_IC_DOCUMENT`, `TYPE_BANK_STATEMENT`, `ALLOWED_FOR_ADMIN`, `ALLOWED_FOR_PPM`, `ALLOWED_FOR_FINANCE` sebagai constants dalam model — satu tempat yang autoriti untuk semua rules.
- Kemaskini `DocumentDownloadController::admin()` guna `ALLOWED_FOR_ADMIN` — jenis baharu perlu didaftarkan secara eksplisit untuk Admin dapat akses.
- Kemaskini `DocumentDownloadController::finance()` guna `ALLOWED_FOR_FINANCE` — logik sama, kini guna constant.
- Kemaskini `ApplicationReviewController::downloadDocument()`:
- Tambah `ALLOWED_FOR_PPM` type check → 403 jika jenis tidak dibenarkan.
- Tukar ownership check dari 404 → 403 (tidak mendedahkan kewujudan ID dokumen).
- Tambah activity log `document_downloaded_by_ppm`.
- Tambah 9 ujian baharu dalam `DocumentDownloadAuthorizationTest` meliputi semua tiga path dan kes utama:
- Admin: ic_document ✓, bank_statement ✓, peranan tidak dibenarkan ✗.
- Finance: bank_statement ✓, ic_document ✗.
- PPM: ic_document (pusat sendiri) ✓, bank_statement (pusat sendiri) ✓, dokumen pusat lain ✗, activity log disimpan.
Fail berubah:
- `app/Models/ApplicationDocument.php` — tambah type constants dan allowlist
- `app/Http/Controllers/DocumentDownloadController.php` — explicit type checks via constants
- `app/Http/Controllers/Ppm/ApplicationReviewController.php` — type check, 403, activity log
- `tests/Feature/DocumentDownloadAuthorizationTest.php` — tulis semula dengan 9 ujian komprehensif
- `docs/04-rbac-permission-matrix.md`
- `docs/decision-log.md`
- `docs/09-improvement-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan test` — 103 tests, 342 assertions (**semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Seterusnya:
- Fasa 14: Portal status permohonan pemohon awam.
- Fasa 15: Purge automatik fail eksport sensitif.
## 2026-06-02 - Fasa 14-A: Portal Status Permohonan Pemohon Awam
Status: Selesai
Selesai:
- Tambah route `GET /permohonan/{publicUuid}/status` tanpa route model binding untuk elak 404 mendedahkan kewujudan UUID.
- Tambah `PublicApplicationController::status()` yang mengendalikan semua kes dengan selamat:
- UUID tidak wujud → 200 dengan mesej generik.
- Rekod soft-deleted → 200 dengan mesej generik.
- Status `deleted_by_ktm` → 200 dengan mesej generik (tidak dedahkan status dalaman).
- Rekod aktif → 200 dengan data terhad.
- Tambah `SensitiveData::maskName()` — tunjuk 3 aksara pertama sahaja.
- Cipta view `public/applications/status.blade.php` memaparkan: nama disamarkan, jawatan dipohon, jawatan diluluskan (jika berbeza), pusat mengundi, badge status dengan warna, sebab penolakan (jika ditolak), nombor rujukan UUID.
- Kemaskini `success.blade.php` dengan panel simpan pautan status dan butang salin URL ke clipboard.
- Tambah 9 ujian baharu dalam `PublicApplicationStatusTest`:
- submitted, assigned, rejected (dengan sebab), UUID tidak dikenali, deleted_by_ktm, soft-deleted — semuanya.
- Nama penuh tidak dipaparkan, IC tidak dipaparkan.
- Halaman boleh dicapai tanpa log masuk.
- Success page paparkan pautan status.
Fail berubah:
- `app/Http/Controllers/PublicApplicationController.php` — tambah `status()`
- `app/Support/SensitiveData.php` — tambah `maskName()`
- `resources/views/public/applications/status.blade.php` (baharu)
- `resources/views/public/applications/success.blade.php` — tambah panel pautan status
- `routes/web.php` — route baharu
- `tests/Feature/PublicApplicationStatusTest.php` (baharu)
- `docs/05-workflow-design.md`
- `docs/06-ui-ux-plan.md`
- `docs/decision-log.md`
- `docs/09-improvement-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan test` — 112 tests, 364 assertions (**semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Seterusnya:
- Fasa 15: Purge automatik fail eksport sensitif.
## 2026-06-02 - Fasa 15-A: Purge Automatik Fail Eksport Sensitif
Status: Selesai
Selesai:
- Tambah kolum `purged_at` (nullable timestamp) dan `purged_by_user_id` (nullable FK) pada `export_logs` melalui migration `2026_06_02_000001_add_purged_at_to_export_logs.php`.
- Kemaskini model `ExportLog` dengan cast `purged_at` dan relationship `purgedBy()`.
- Cipta Artisan command `ExportPurgeCommand` (`php artisan exports:purge --days=30`):
- Query `export_logs` di mana `created_at < now - days` DAN `purged_at IS NULL`.
- Padam fail dari storage disk yang berkaitan.
- Rekod yang filenya sudah tiada di disk tetap ditandakan `purged_at` supaya tidak diproses semula.
- Log aktiviti `export_file_purged` untuk setiap rekod.
- Lapor bilangan fail dipadamkan dan rekod tiada fail.
- Daftarkan command sebagai scheduled task harian pada `00:00` dalam `routes/console.php` (`--days=30`, withoutOverlapping, runInBackground).
- Tambah 7 ujian baharu dalam `ExportPurgeCommandTest`:
- Fail lama dipadamkan, `purged_at` ditetapkan.
- Fail dalam tempoh simpanan tidak disentuh.
- Rekod tanpa fail (`missing`) tetap ditandakan `purged_at`.
- Rekod yang sudah `purged_at` tidak diproses semula.
- `--days` custom berfungsi.
- Activity log direkod.
- `--days=0` gagal dengan exit code bukan 0.
Fail berubah:
- `database/migrations/2026_06_02_000001_add_purged_at_to_export_logs.php` (baharu)
- `app/Models/ExportLog.php` — tambah cast + relationship
- `app/Console/Commands/ExportPurgeCommand.php` (baharu)
- `routes/console.php` — scheduled task
- `tests/Feature/ExportPurgeCommandTest.php` (baharu)
- `docs/03-database-design.md`
- `docs/08-deployment-notes.md`
- `docs/decision-log.md`
- `docs/09-improvement-plan.md`
- `docs/progress-log.md`
- `docs/changelog.md`
Semakan:
- `php artisan migrate` — lulus.
- `php artisan test` — 119 tests, 388 assertions (**semua lulus**).
- `vendor\bin\pint.bat --test` — lulus.
- `vendor\bin\phpstan.bat analyse --memory-limit=1G` — lulus, 0 error.
Semua fasa selesai (12-A hingga 15-A). Sistem sedia untuk UAT.