# Deploying InLynq on cPanel

This guide assumes standard cPanel shared hosting. It works whether or not your plan includes **Terminal/SSH**. Where a step needs a command, both ways are shown.

Throughout, `USERNAME` is your cPanel username and `yourdomain.com` is your domain.

---

## 0. Check your hosting

In cPanel, open **Select PHP Version** (or **MultiPHP Manager**):

- **PHP 8.3 or 8.4**: required.
- Extensions to tick: `pdo_mysql`, `mysqlnd`, `mbstring`, `openssl`, `fileinfo`, `gd`, `tokenizer`, `ctype`, `curl`, `dom`, `xml`, `zip`, `bcmath`, `intl`.
- In the PHP **Options** tab, set `memory_limit` to 256M and `upload_max_filesize`/`post_max_size` to 12M.

You also need a MySQL 8 or MariaDB 10.6+ database (standard on cPanel).

## 1. Create the database

**cPanel → MySQL® Databases**

1. Create a database, e.g. `inlynq`. cPanel names it `USERNAME_inlynq`.
2. Create a user with a long random password. cPanel names it `USERNAME_inlynq`.
3. **Add User To Database** → tick **ALL PRIVILEGES**.

Write down the database name, username and password.

## 2. Upload the files

The zip contains:

```
inlynq/                  ← the application
public_html-option/      ← only needed for Option B below
DEPLOY_CPANEL.md         ← this guide
```

**cPanel → File Manager**

1. Go to your **home folder** (`/home/USERNAME`). Don't open `public_html`.
2. **Upload** `inlynq-cpanel.zip`, then right-click it and choose **Extract**.
3. You now have `/home/USERNAME/inlynq`. Keeping the app outside `public_html` means `.env`, source code and uploads of private documents are never web-accessible.

## 3. Point the domain at the app

Pick **one** option.

### Option A — recommended: point the document root at `inlynq/public`

**cPanel → Domains** → find your domain → **Manage** → set **Document Root** to `inlynq/public` → **Update**.
(For an addon domain or subdomain, set its document root to `inlynq/public` when you create it.)

That's all; skip to step 4.

### Option B — your host forces the domain to use `public_html`

1. Move everything inside `/home/USERNAME/inlynq/public/` into `/home/USERNAME/public_html/`, including the hidden `.htaccess`. In File Manager, use **Settings → Show Hidden Files**.
2. Replace `public_html/index.php` with the `index.php` from `public_html-option/`.
3. If you named the app folder something other than `inlynq`, edit the `$app_path` line in that file.

> Under Option B, uploads are stored in `public_html/uploads` and the built assets in `public_html/build`. When you update the app later, re-copy `inlynq/public/build` into `public_html/build`.

## 4. Configure `.env`

In File Manager, inside `/home/USERNAME/inlynq`:

1. Rename **`.env.cpanel`** to **`.env`** (Show Hidden Files must be on).
2. Edit `.env` and replace every `CHANGE_ME`:
   - `APP_URL=https://yourdomain.com` (use https, no trailing slash)
   - `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD` from step 1
   - Mail settings: **cPanel → Email Accounts** → create `hello@yourdomain.com` → **Connect Devices** shows the server, port and password to use for `MAIL_HOST`, `MAIL_PORT`, `MAIL_USERNAME` and `MAIL_PASSWORD`
   - Paystack keys (step 8). You can leave them as test keys for now.
   - `SEED_ADMIN_EMAIL` / `SEED_ADMIN_PASSWORD`: your admin login
3. `APP_KEY` is already filled with a freshly generated key. Keep it secret and don't change it once users exist.

## 5. Install the database tables

### With Terminal (cPanel → Terminal, or SSH)

```bash
cd ~/inlynq
php artisan migrate --force
php artisan db:seed --class=PlanSeeder --force
php artisan db:seed --class=AdminSeeder --force
php artisan optimize
```

If `php` points to an old version, use the full path your host shows in **MultiPHP Manager**, e.g. `/opt/cpanel/ea-php83/root/usr/bin/php` (or `/usr/local/bin/ea-php83`).

### Without Terminal (using a one-off cron job)

**cPanel → Cron Jobs** → add a job set to **Once Per Minute** with this command:

```
cd /home/USERNAME/inlynq && php artisan migrate --force && php artisan db:seed --class=PlanSeeder --force && php artisan db:seed --class=AdminSeeder --force && php artisan optimize > /home/USERNAME/inlynq/storage/logs/install.log 2>&1
```

Wait two minutes, check `storage/logs/install.log` in File Manager for "DONE" lines, then **delete this cron job**.

## 6. Add the scheduler cron (keep this one)

**cPanel → Cron Jobs** → **Once Per Minute**:

```
cd /home/USERNAME/inlynq && php artisan schedule:run >> /dev/null 2>&1
```

This one cron runs everything:

- queued jobs (emails, image thumbnails, analytics, Paystack webhooks), because `QUEUE_VIA_SCHEDULER=true`
- daily analytics roll-ups, billing reconciliation, verification expiry and media cleanup

Without it, emails won't send and payments confirmed by webhook will wait until the next checkout poll.

## 7. Turn on HTTPS

**cPanel → SSL/TLS Status** → **Run AutoSSL** for your domain. Open `https://yourdomain.com`. You should see the InLynq landing page.

Log in at `https://yourdomain.com/login` with the `SEED_ADMIN_*` details. The admin area is at `/admin`.

## 8. Paystack

1. Paystack dashboard → **Settings → API Keys & Webhooks**.
2. Copy the **Public** and **Secret** keys into `.env` (`PAYSTACK_PUBLIC_KEY`, `PAYSTACK_SECRET_KEY`). Start with test keys.
3. Set **Webhook URL** to `https://yourdomain.com/webhooks/paystack`.
4. After any `.env` change, refresh the config cache: run `php artisan optimize` (Terminal), or use the one-off cron trick from step 5 with just `cd /home/USERNAME/inlynq && php artisan optimize`.
5. Test: log in as a normal user → **Billing → Upgrade** → pay with a Paystack test card. Within a minute the plan should show as active.

Switch to live keys (`pk_live_…`/`sk_live_…`) when you're ready to take real payments, and run `php artisan optimize` again.

## 9. Updating the site later

1. On your computer: `bash deploy/build-cpanel.sh` → upload the new zip → extract over `/home/USERNAME/inlynq`. Your `.env`, `storage/` and `public/uploads/` are not in the zip, so they're kept.
2. Option B only: re-copy `inlynq/public/build` into `public_html/build`.
3. Run `php artisan migrate --force && php artisan optimize` (Terminal, or the one-off cron).

## Troubleshooting

| Symptom | Fix |
|---|---|
| **500 error** on every page | Check `storage/logs/laravel-*.log`. Usually wrong DB details in `.env`, or `storage/` not writable: set `storage` and `bootstrap/cache` folders to permission **755** (775 on some hosts). |
| **"Please provide a valid cache path"** | The folders `storage/framework/{cache,sessions,views}` are missing. Create them. |
| Changed `.env` but nothing changed | Run `php artisan optimize` (config is cached). |
| Page has no styling | Option A: the document root isn't `inlynq/public`. Option B: `public_html/build` is missing. |
| **419 Page expired** on forms | `APP_URL` must match the address in the browser exactly (https and www or not). Keep `SESSION_SECURE_COOKIE=true` only when the site is on https. |
| Emails not arriving | The scheduler cron (step 6) isn't running, or the mail settings are wrong. Check `storage/logs`. |
| Payment stays "pending" | Check the webhook URL in Paystack and that the cron is running. Admins can press **Re-verify with Paystack** on the payment in `/admin/payments`. |
| Uploaded photos 404 | Make sure `inlynq/public/uploads` (Option A) or `public_html/uploads` (Option B) exists and is writable (755). |
| Site behind Cloudflare shows wrong visitor data or redirect loops | Set `TRUSTED_PROXIES=*` and use Cloudflare SSL mode **Full (strict)**. |

## What shared hosting doesn't give you

The app is configured for shared hosting (database cache, sessions and queue; cron-driven jobs; no symlinks). It runs well for an early-stage product. When traffic grows, move to a VPS with Redis and a real queue worker. The main `README.md` covers that setup.
