# Production deployment

## Topology

Use Nginx → PHP-FPM application nodes, MySQL/MariaDB, Redis cache/session/queue,
S3-compatible private storage, SMTP, Supervisor queue workers, and the Laravel
scheduler. Terminate TLS at the load balancer or Nginx and forward HTTPS correctly.

For a cPanel-style plan without Redis, use the database-backed shared-hosting profile
and installation procedure in `deploy/shared-hosting/README.md`. The plan must provide
PHP 8.2+, MySQL/MariaDB, HTTPS, cron, terminal/SSH access, and a document root pointed
at `public`.

## First deployment

1. Create `/var/www/university-erp/{releases,shared/storage}` owned by the deploy user
   and writable by `www-data` where required.
2. Put the production `.env` at `shared/.env`.
3. Install `deploy/nginx.conf`, `deploy/supervisor-worker.conf`, and
   `deploy/university-erp-scheduler.service`, replacing domains/paths.
4. Upload a release to a timestamped `releases/` directory.
5. Run `APP_ROOT=/var/www/university-erp deploy/deploy.sh /absolute/release`.
6. Verify `/up`, `/ready`, authentication, queues, scheduler, email, private storage,
   payment sandbox callbacks, and one authorized download.

The script installs locked dependencies, builds assets, caches Laravel configuration,
runs forward-compatible migrations, atomically switches the symlink, restarts queues,
and rolls application code back if readiness fails.

## Rollback

Run `deploy/rollback.sh /absolute/previous-release`. It never performs a destructive
database rollback. Database changes must be backward compatible across adjacent
releases; corrective migrations are preferred.

## Release checklist

Require code review, passing tests/audits/build, current backups, a restore rehearsal,
migration review, maintenance communication, monitoring, and a named rollback owner.
After deployment inspect error rate, response latency, slow queries, queue depth,
failed jobs, storage, webhook failures, and mail delivery.
