6.6 KiB
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;npmPowerShell shim is blocked by execution policy. - MySQL CLI is not available in PATH and must be confirmed before database setup.
pdo_mysqlPHP extension is available.- MySQL 8.4.8 connection was confirmed through Laravel/PDO during Phase 2.
- Local
.envis configured for MySQL databaseprn2026.
Environment Configuration
Required .env values:
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:
- Pull or upload application source.
- Install Composer dependencies without dev packages.
- Install/build frontend assets.
- Configure
.env. - Generate app key if not already configured.
- Run migrations.
- Run seeders for roles, permissions, positions, and initial Admin user where appropriate.
- Cache configuration, routes, and views.
- Start queue worker.
- Configure scheduler.
- Validate login and critical workflows.
Planned commands:
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):
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
To run purge manually:
php artisan exports:purge --days=30
php artisan exports:purge --days=7 # shorter retention for testing
Security Checklist
APP_DEBUG=falsein 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:
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:
-- 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:
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:
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.
.envsecurely 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.mdfor user-facing changes.docs/progress-log.mdfor implementation phase completion.docs/decision-log.mdfor architecture, database, security, and package decisions.