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

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; 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:

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:

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=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:

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.
  • .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.