248 lines
6.6 KiB
Markdown
248 lines
6.6 KiB
Markdown
# Deployment Notes
|
|
|
|
## Target Environment
|
|
|
|
The application is intended for a standard Laravel production deployment using:
|
|
|
|
- PHP compatible with selected Laravel version.
|
|
- Composer.
|
|
- MySQL.
|
|
- Web server such as Nginx or Apache.
|
|
- Node/npm only for building frontend assets, not necessarily required on production runtime if assets are built during deployment.
|
|
- Queue worker for mail and background jobs.
|
|
- Scheduler for Laravel scheduled tasks where needed.
|
|
|
|
## Local Environment Findings
|
|
|
|
Inspection date: 2026-05-28
|
|
|
|
- PHP CLI: 8.5.1.
|
|
- Composer: 2.9.4.
|
|
- Node: 25.1.0.
|
|
- npm works through `npm.cmd`; `npm` PowerShell shim is blocked by execution policy.
|
|
- MySQL CLI is not available in PATH and must be confirmed before database setup.
|
|
- `pdo_mysql` PHP extension is available.
|
|
- MySQL 8.4.8 connection was confirmed through Laravel/PDO during Phase 2.
|
|
- Local `.env` is configured for MySQL database `prn2026`.
|
|
|
|
## Environment Configuration
|
|
|
|
Required `.env` values:
|
|
|
|
```text
|
|
APP_NAME="Sistem Pengurusan Pusat Mengundi"
|
|
APP_ENV=production
|
|
APP_KEY=
|
|
APP_DEBUG=false
|
|
APP_URL=
|
|
APP_TIMEZONE=Asia/Kuala_Lumpur
|
|
|
|
DB_CONNECTION=mysql
|
|
DB_HOST=
|
|
DB_PORT=3306
|
|
DB_DATABASE=
|
|
DB_USERNAME=
|
|
DB_PASSWORD=
|
|
|
|
QUEUE_CONNECTION=database
|
|
MAIL_MAILER=
|
|
MAIL_HOST=
|
|
MAIL_PORT=
|
|
MAIL_USERNAME=
|
|
MAIL_PASSWORD=
|
|
MAIL_ENCRYPTION=
|
|
MAIL_FROM_ADDRESS=
|
|
MAIL_FROM_NAME=
|
|
FILESYSTEM_DISK=local
|
|
|
|
SEED_ADMIN_NAME="Admin Sistem"
|
|
SEED_ADMIN_EMAIL=admin@prn.local
|
|
SEED_ADMIN_PASSWORD=password
|
|
```
|
|
|
|
Production must override the seeded Admin password before deployment or disable default seeding after the first secure Admin account is created.
|
|
|
|
## Storage
|
|
|
|
Sensitive documents:
|
|
|
|
- IC document.
|
|
- Bank statement.
|
|
|
|
Rules:
|
|
|
|
- Store sensitive documents on private disk.
|
|
- Do not expose sensitive uploads through public storage symlink.
|
|
- Serve document downloads through authorized controller actions only.
|
|
- Use secure file validation for MIME type, extension, and size.
|
|
|
|
## Deployment Steps
|
|
|
|
Initial production deployment should follow this sequence:
|
|
|
|
1. Pull or upload application source.
|
|
2. Install Composer dependencies without dev packages.
|
|
3. Install/build frontend assets.
|
|
4. Configure `.env`.
|
|
5. Generate app key if not already configured.
|
|
6. Run migrations.
|
|
7. Run seeders for roles, permissions, positions, and initial Admin user where appropriate.
|
|
8. Cache configuration, routes, and views.
|
|
9. Start queue worker.
|
|
10. Configure scheduler.
|
|
11. Validate login and critical workflows.
|
|
|
|
Planned commands:
|
|
|
|
```bash
|
|
composer install --no-dev --optimize-autoloader
|
|
npm.cmd ci
|
|
npm.cmd run build
|
|
php artisan key:generate
|
|
php artisan migrate --force
|
|
php artisan db:seed --force
|
|
php artisan config:cache
|
|
php artisan route:cache
|
|
php artisan view:cache
|
|
php artisan queue:restart
|
|
```
|
|
|
|
Commands may need adjustment for the actual hosting environment.
|
|
|
|
## Queue Worker
|
|
|
|
Queue should handle:
|
|
|
|
- KTM-created applicant email notifications.
|
|
- Potentially larger exports.
|
|
- Future notification jobs.
|
|
|
|
Recommended:
|
|
|
|
- Use database queue initially for simplicity.
|
|
- Use Supervisor, Windows service wrapper, or hosting panel worker support to keep queue running.
|
|
|
|
## Scheduler
|
|
|
|
Active scheduled tasks:
|
|
|
|
| Command | Schedule | Purpose |
|
|
|---|---|---|
|
|
| `exports:purge --days=30` | Daily at 00:00 | Purge export files older than 30 days |
|
|
|
|
To change the retention period, edit `routes/console.php` and update `--days=30`.
|
|
|
|
Scheduler entry (add to OS cron):
|
|
|
|
```bash
|
|
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
|
|
```
|
|
|
|
To run purge manually:
|
|
|
|
```bash
|
|
php artisan exports:purge --days=30
|
|
php artisan exports:purge --days=7 # shorter retention for testing
|
|
```
|
|
|
|
## Security Checklist
|
|
|
|
- `APP_DEBUG=false` in production.
|
|
- Strong database credentials.
|
|
- HTTPS enabled.
|
|
- Private document storage.
|
|
- Correct file permissions for storage and cache.
|
|
- Document downloads must use authorized controller routes; do not expose `storage/app/private`.
|
|
- Admin Kewangan document access is limited to bank statements.
|
|
- Queue worker runs under least-privilege user.
|
|
- Audit log retention policy defined.
|
|
- Regular backups.
|
|
- Admin accounts reviewed before launch.
|
|
- Default development accounts removed or password-changed.
|
|
|
|
## Index Verification After Migration
|
|
|
|
After running migrations on a fresh database, verify the performance indexes exist:
|
|
|
|
```sql
|
|
SHOW INDEX FROM applications WHERE Key_name IN (
|
|
'app_election_status_idx',
|
|
'app_ktm_position_idx'
|
|
);
|
|
|
|
SHOW INDEX FROM staff_assignments WHERE Key_name IN (
|
|
'sa_election_pusat_position_idx',
|
|
'sa_election_saluran_position_idx',
|
|
'sa_reports_to_pos_status_idx'
|
|
);
|
|
```
|
|
|
|
All of the above should return rows. If any are missing, re-run `php artisan migrate`.
|
|
|
|
Use `EXPLAIN` on critical service queries to confirm index usage:
|
|
|
|
```sql
|
|
-- KtmVacancyService: reserved application count
|
|
EXPLAIN SELECT * FROM applications
|
|
WHERE selected_ktm_assignment_id = ? AND requested_position_id = ?
|
|
AND status IN ('submitted', 'under_ppm_review', 'approved');
|
|
|
|
-- KtmVacancyService: active KP count under a KTM
|
|
EXPLAIN SELECT COUNT(*) FROM staff_assignments
|
|
WHERE reports_to_assignment_id = ? AND position_id = ? AND status = 'active';
|
|
```
|
|
|
|
Both should show `key` as the respective composite index, not NULL.
|
|
|
|
## Final Quality Gate
|
|
|
|
Run before production release:
|
|
|
|
```bash
|
|
php artisan route:list --except-vendor
|
|
php artisan test
|
|
vendor/bin/pint --test
|
|
vendor/bin/phpstan analyse --memory-limit=1G
|
|
npm.cmd run build
|
|
```
|
|
|
|
The Windows local environment uses `.bat` wrappers for vendor binaries:
|
|
|
|
```bash
|
|
vendor\bin\pint.bat --test
|
|
vendor\bin\phpstan.bat analyse --memory-limit=1G
|
|
```
|
|
|
|
## Backup Checklist
|
|
|
|
Back up:
|
|
|
|
- MySQL database.
|
|
- Private storage documents.
|
|
- Export files if retained.
|
|
- `.env` securely through infrastructure secret management, not public repository.
|
|
|
|
Recommended frequency:
|
|
|
|
- Daily database backups during active registration and polling period.
|
|
- More frequent backup before and on polling day.
|
|
- Storage backup aligned with database backups.
|
|
|
|
## Performance Notes
|
|
|
|
- Use server-side pagination for large lists.
|
|
- Add indexes for election, Pusat Mengundi, status, role, and IC lookup.
|
|
- Avoid loading documents or large relationship graphs on index pages.
|
|
- Use queued exports if datasets become large.
|
|
- Cache role/permission checks through Spatie package defaults.
|
|
- Keep attendance, finance, Admin management, and setup index pages paginated.
|
|
- For very large datasets, move XLSX exports to queued jobs and notify users when complete.
|
|
|
|
## Release Notes Process
|
|
|
|
Every deployment should update:
|
|
|
|
- `docs/changelog.md` for user-facing changes.
|
|
- `docs/progress-log.md` for implementation phase completion.
|
|
- `docs/decision-log.md` for architecture, database, security, and package decisions.
|