# cPanel Staging Deployment

This procedure deploys Phase 1 to a private staging location while the current ZumaX website remains untouched.

## 1. Preserve the current site

1. Download a backup of the existing `public_html` website and its current host-ready ZIP.
2. Do not overwrite, move, or delete the existing public site.
3. Create a staging subdomain such as `office-staging.zumaxenterprises.com` or a private test domain.
4. Protect staging with cPanel Directory Privacy or an equivalent access restriction in addition to the application login.

## 2. Set a safe document root

Recommended layout:

```text
/home/CPANEL_USER/apps/zumax-platform-phase1/       Laravel application
/home/CPANEL_USER/apps/zumax-platform-phase1/public Web document root
```

Point the staging subdomain document root to the application's `public/` directory. The web server must never expose `.env`, `vendor/`, `storage/`, migrations, or application source. If the hosting plan cannot point a domain at `public/`, ask the host to configure it; do not upload the entire Laravel application into a publicly browsable directory.

## 3. Check the server

In cPanel, select PHP 8.3 or later and enable the extensions required by Laravel: Ctype, cURL, DOM, Fileinfo, Filter, Hash, Mbstring, OpenSSL, PCRE, PDO, PDO MySQL, Session, Tokenizer, and XML. Confirm that Composer 2 is available in Terminal or through the host.

## 4. Upload and install dependencies

Extract the Phase 1 ZIP into the private application directory. From that directory:

```bash
composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction
composer validate --strict
composer audit
cp .env.example .env
php artisan key:generate
```

Never copy a real `.env` into a support ticket, Git repository, or public folder. Back up `APP_KEY` securely after setup: changing it later makes existing encrypted 2FA secrets and sessions unreadable.

The first dependency installation creates `composer.lock` when the source archive has none. Preserve that generated lock file with the tested release so later deployments reproduce the accepted dependency set; review updates on staging rather than resolving new versions during a production cutover.

## 5. Create the database

Use cPanel MySQL Databases to create a database and a dedicated least-privilege user. Grant that user privileges only on this database. Update `.env`:

```dotenv
APP_ENV=staging
APP_DEBUG=false
APP_URL=https://office-staging.zumaxenterprises.com
APP_TIMEZONE=Africa/Dar_es_Salaam

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=CPANEL_PREFIX_zumax
DB_USERNAME=CPANEL_PREFIX_zumax_user
DB_PASSWORD=REPLACE_WITH_A_LONG_RANDOM_PASSWORD

SESSION_SECURE_COOKIE=true
ZUMAX_SITE_ENV=staging
ZUMAX_FOUNDATION_MODE=true
ZUMAX_TRUSTED_HOSTS=office-staging.zumaxenterprises.com
ZUMAX_IP_HASH_KEY=REPLACE_WITH_A_SEPARATE_RANDOM_SECRET
```

Generate `ZUMAX_IP_HASH_KEY` with the host's secure random generator, for example `openssl rand -hex 32`. It is used only to create non-reversible, deployment-specific IP fingerprints in the activity trail.

## 6. Configure ZumaX mail identities

Phase 1 does not send contact-form content. SMTP is used only for account recovery. Configure the authenticated `no-reply@zumaxenterprises.com` sending identity:

```dotenv
MAIL_MAILER=smtp
MAIL_SCHEME=null
MAIL_HOST=mail.zumaxenterprises.com
MAIL_PORT=587
MAIL_USERNAME=no-reply@zumaxenterprises.com
MAIL_PASSWORD=REPLACE_WITH_THE_MAILBOX_OR_SMTP_PASSWORD
MAIL_FROM_ADDRESS=no-reply@zumaxenterprises.com
MAIL_FROM_NAME="ZumaX Enterprises"
```

Keep `info@zumaxenterprises.com` for project enquiries and `support@zumaxenterprises.com` for existing-client support. Publish valid SPF, DKIM, and DMARC records for dependable password-reset delivery. Do not use `info@` as the automated sender.

## 7. Prepare writable directories and database

Use permissions suitable for the host's PHP handler; do not use `777`:

```bash
chmod -R u+rwX storage bootstrap/cache
php artisan migrate --seed --force
php artisan zumax:create-owner
```

The Owner command asks for the password interactively, enforces a strong minimum, refuses to create a second active Owner, and does not expose the password in shell history or process arguments.

## 8. Cache and schedule

```bash
php artisan optimize
php artisan about
php artisan route:list --path=office
```

Add this cPanel cron job once per minute, adjusting paths and the PHP binary to the host:

```cron
* * * * * /usr/local/bin/php /home/CPANEL_USER/apps/zumax-platform-phase1/artisan schedule:run >> /dev/null 2>&1
```

Phase 1 has no business cleanup job yet; adding the scheduler now makes later expiry and retention jobs predictable.

Set and document retention for cPanel/Apache access logs and expired database sessions. Durable ZumaX activity records use keyed IP hashes, but the host access log and an active Laravel session can temporarily contain a raw source IP for security operations.

## 9. Staging acceptance checks

1. Open `/up`; it should return a successful health response.
2. Open `/`; verify the homepage, responsive header controls, logo, favicon, dark/light theme, and legal pages.
3. Confirm that the contact form is disabled and visibly says no data is stored or emailed.
4. Open `/office/register`; it must return 404.
5. Sign in at `/office/login` as the Owner.
6. Confirm that `/office` redirects to `/office/security` until TOTP setup is completed.
7. Scan the QR code, save recovery codes, confirm a six-digit code, sign out, and sign in again.
8. Review People & roles and Activity trail.
9. Trigger one failed sign-in and confirm a warning event appears without the password or raw IP address.
10. Request a password reset and verify delivery, expiry behavior, and the new password rules.

Run the full automated suite before approval:

```bash
php artisan test
```

## 10. Backups and rollback

Before every migration, export the staging database and archive `.env` in an encrypted private backup. To roll back Phase 1 staging, disable the staging subdomain or point it back to its previous document root and restore the database export. The existing public website remains the fallback because this deployment never replaces it.

Do not announce or perform a production cutover from this Phase 1 build. The verified database-backed enquiry workflow belongs to Phase 2.
