# ICOMAN on cPanel shared hosting

This guide assumes only cPanel File Manager, phpMyAdmin, Cron Jobs, SSL/TLS Status, and optionally cPanel Terminal are available. It does not require SSH or root access.

## 1. Hosting requirements

Select **PHP 8.1 or 8.2** in cPanel MultiPHP Manager. PHP 8.0 is supported by the current code but is end-of-life and must not be used for a new production deployment.

Enable these extensions in **Select PHP Version** (names vary by host): `bcmath`, `ctype`, `curl`, `dom`, `fileinfo`, `json`, `mbstring`, `openssl`, `pdo`, `pdo_mysql`, `tokenizer`, `xml`, and `zip`. Enable `exif` if staff photo uploads are later added.

Use MySQL 8.0+ or MariaDB 10.4+. Confirm `max_allowed_packet` is sufficient for the permitted 20 MiB import file size; 32 MiB or higher is a sensible minimum. Ask the hosting provider to change this if it is unavailable in cPanel.

## 2. Put only `public/` on the web

1. Upload the complete release under a non-public path such as `/home/CPANEL_USER/icoman` using File Manager. Do **not** upload it directly into `public_html`.
2. In cPanel **Domains**, set the domain/subdomain document root to `/home/CPANEL_USER/icoman/public`.
3. If the host cannot change a document root, use a separate subdomain whose document root can be set to that directory. Do not copy `artisan`, `.env`, `vendor`, `app`, `bootstrap`, `config`, `database`, or `storage` into `public_html`.
4. Confirm `https://YOUR_DOMAIN/healthz` works after configuration. It reports only `status`; it exposes no configuration values.

The repository `.htaccess` rules in `public/` are used by Apache/LiteSpeed. Ensure `mod_rewrite` is enabled (most cPanel hosts enable it by default).

## 3. Build and upload a release without SSH

Build dependencies in CI or on a trusted workstation, then upload the resulting release archive with `vendor/` included. Do not run `composer install` through a browser or expose Composer endpoints.

Before packaging, use the exact production PHP major/minor version where possible and run:

```text
composer install --no-dev --prefer-dist --optimize-autoloader
php artisan config:clear
php artisan route:clear
php artisan view:clear
```

If cPanel Terminal is available, those commands may instead run there after upload. Terminal is optional; it is not SSH/root access.

## 4. Create the database

1. Open **MySQL Database Wizard** and create a database, database user, and a long random password.
2. Grant the user **ALL PRIVILEGES** only on the ICOMAN database.
3. Record the cPanel-prefixed database and user names (for example `account_icoman`), not the display names entered in the wizard.
4. Run migrations once through cPanel Terminal:

```text
cd /home/CPANEL_USER/icoman
php artisan migrate --force
```

If Terminal is unavailable, generate a production schema SQL export in CI/a trusted staging environment after running the same migrations, review it, and import it in **phpMyAdmin**. Import the schema only; never import a development `.env`, users, or production data. Repeat this controlled export/import process for future migration releases.

The `jobs` table migration is included so the shared-hosting database queue fallback can be used.

## 5. Environment configuration

Copy `.env.example` to `.env` in `/home/CPANEL_USER/icoman` with File Manager and edit it there. Never place `.env` in `public/`, attach it to tickets, or commit it.

Minimum production values:

```dotenv
APP_NAME=ICOMAN
APP_ENV=production
APP_KEY=base64:GENERATE_A_UNIQUE_VALUE
APP_DEBUG=false
APP_URL=https://YOUR_DOMAIN

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=CPANELPREFIX_icoman
DB_USERNAME=CPANELPREFIX_icoman
DB_PASSWORD=USE_A_LONG_RANDOM_PASSWORD

CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_SECURE_COOKIE=true
SESSION_ENCRYPT=true
SESSION_EXPIRE_ON_CLOSE=true
QUEUE_CONNECTION=database
MAIL_MAILER=smtp
MAIL_HOST=YOUR_SMTP_HOST
MAIL_PORT=587
MAIL_USERNAME=YOUR_SMTP_USERNAME
MAIL_PASSWORD=YOUR_SMTP_PASSWORD
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@YOUR_DOMAIN
MAIL_FROM_NAME="ICOMAN"
```

Generate `APP_KEY` in cPanel Terminal with `php artisan key:generate --show`, then paste the value into `.env`. If no Terminal exists, generate a Laravel-compatible base64 key in the approved deployment pipeline/secret manager and paste it via File Manager. Never use a public key-generation website.

After editing `.env`, when Terminal is available run `php artisan config:cache`, `php artisan route:cache`, and `php artisan view:cache`. Without Terminal, leave these caches uncached; the application remains functional.

## 6. Permissions and storage link

Set the owner to the cPanel account. In File Manager, set these directories to **0755** (or **0775** only if the host requires group write access):

- `storage`
- `storage/app`
- `storage/framework`
- `storage/framework/cache`
- `storage/framework/sessions`
- `storage/framework/views`
- `storage/logs`
- `bootstrap/cache`

Never use `0777` unless the host’s support team confirms it is unavoidable and explains why. Keep documents/imports on the `local` disk (`storage/app`), which is outside the document root.

Run `php artisan storage:link` only if the application needs public photos/assets. If Terminal is unavailable, create a cPanel File Manager symbolic link named `public/storage` pointing to `../storage/app/public` **only** when public assets are required. Do not link `storage/app`, `storage/logs`, imports, reports, or private member documents.

## 7. Cron, scheduler, and queue fallback

In **cPanel → Cron Jobs**, use the PHP binary shown by the host (often `/usr/local/bin/php` or `/opt/cpanel/ea-php81/root/usr/bin/php`), not a guessed path. Replace the paths below with actual account paths.

Scheduler, every minute:

```cron
* * * * * /opt/cpanel/ea-php81/root/usr/bin/php /home/CPANEL_USER/icoman/artisan schedule:run >> /home/CPANEL_USER/icoman/storage/logs/scheduler.log 2>&1
```

Shared hosting normally cannot maintain a permanent `queue:work` process. Use the database queue and process one short-lived job each minute:

```cron
* * * * * /opt/cpanel/ea-php81/root/usr/bin/php /home/CPANEL_USER/icoman/artisan queue:work database --once --tries=3 --timeout=50 >> /home/CPANEL_USER/icoman/storage/logs/queue.log 2>&1
```

This fallback is appropriate for imports and card rendering at modest shared-hosting volumes. It adds up to roughly one minute of queue latency. If imports become frequent or long-running, move the queue to a managed worker/Redis service or VPS; do not attempt daemon processes on a shared plan.

## 8. SSL and email

Enable **AutoSSL/Let’s Encrypt** in cPanel SSL/TLS Status and force HTTPS using the domain’s cPanel setting or the host’s documented redirect option. Set `APP_URL` to the HTTPS URL and keep `SESSION_SECURE_COOKIE=true`.

Use authenticated SMTP from the domain mail provider or transactional-mail provider. Test a real reset/notification email after deployment, verify SPF/DKIM, and keep SMTP credentials only in `.env`.

## 9. Backup and recovery

Use cPanel Backup or JetBackup to create at least daily database and application-storage backups. Include private `storage/app` files, but exclude reproducible directories such as `vendor` if backup space is limited. Keep an encrypted off-host copy with 35 daily restore points and 12 monthly restore points. Test a database plus storage restore into a staging subdomain quarterly.

Before each release: export the database from phpMyAdmin, download a copy of `storage/app`, deploy the new release, run/import migrations, then check `/healthz`, login, verification, and queued imports. Keep the preceding release archive until smoke checks pass.
