# InterServer / cPanel Deployment

End-to-end deployment on a standard InterServer shared or VPS cPanel account.

---

## Step 1 — Verify PHP version

**cPanel → Software → Select PHP Version**

Set to **PHP 8.1 or newer** (8.2 recommended). Then under **Extensions**, confirm these are checked:

- `pdo_mysql`
- `openssl`
- `mbstring`
- `curl`
- `json`
- `fileinfo`
- `gd` *(for image handling)*

Save.

---

## Step 2 — Create the database

**cPanel → Databases → MySQL® Database Wizard**

1. **Database name:** `paddlers` → becomes `cpuser_paddlers`
2. **Username:** `pcapp` → becomes `cpuser_pcapp`
3. **Password:** generate a long one; save it
4. **Privileges:** check **ALL PRIVILEGES** → Next Step

> **Why MySQL and not PostgreSQL?** You already know MySQL, InterServer's cPanel tooling (phpMyAdmin, backups, remote access) is built around it, and nothing in this application needs anything MySQL 8 can't do. The schema uses InnoDB with foreign keys, JSON columns, and FULLTEXT indexes — all fully supported. PostgreSQL would be a better engine in the abstract and a worse choice here, because the first time something breaks at 11 PM you want to be debugging in a tool you know cold.

---

## Step 3 — Upload the application

### Option A — Git (recommended)

**cPanel → Git™ Version Control** → Create → clone your repo to `/home/USER/paddlerscove`

### Option B — File Manager

1. Zip the project locally
2. **File Manager** → navigate to `/home/USER/`
3. Upload, then **Extract** into `/home/USER/paddlerscove`

**Do not put the app inside `public_html`.** Only `public/` should be web-reachable.

Target layout:
```
/home/USER/
├── paddlerscove/          ← application (not web accessible)
│   ├── config/keys/       ← Apple .p8, Google service account JSON
│   ├── src/  views/  database/  bin/  storage/
│   ├── vendor/
│   ├── .env
│   └── public/            ← this is the web root
└── public_html/           ← see Step 5
```

---

## Step 4 — Install Composer dependencies

**cPanel → Terminal** (or SSH):

```bash
cd ~/paddlerscove

# Install Composer locally if it isn't available
curl -sS https://getcomposer.org/installer | php

php composer.phar install --no-dev --optimize-autoloader
```

If Terminal is disabled on your plan, run `composer install` locally and upload the resulting `vendor/` directory.

---

## Step 5 — Point the domain at `public/`

### Best: change the document root

**cPanel → Domains** → find your domain → **Manage** → set **Document Root** to:
```
/home/USER/paddlerscove/public
```

### Fallback: symlink

If your plan won't let you change the docroot:

```bash
rm -rf ~/public_html
ln -s ~/paddlerscove/public ~/public_html
```

### Last resort

Copy everything to `public_html` and rely on the root `.htaccess` included in the project, which rewrites into `public/`. Functional, but it leaves `.env` one misconfiguration away from being served. Use one of the first two options if at all possible.

---

## Step 6 — Create `.env`

```bash
cd ~/paddlerscove
cp .env.example .env
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;"   # paste into APP_KEY
nano .env
```

Fill in at minimum:

```ini
APP_URL="https://paddlerscove.org"
APP_KEY=<the generated string>
DB_NAME=cpuser_paddlers
DB_USER=cpuser_pcapp
DB_PASS=<your db password>
ADMIN_EMAILS="your.email@gmail.com"
NOTIFY_EMAIL="your.email@gmail.com"
```

> `ADMIN_EMAILS` is the bootstrap. The first time you sign in with a federated account whose email is on that list, you're created as an approved admin automatically. No chicken-and-egg problem, no manual SQL.

Lock it down:
```bash
chmod 600 .env
```

---

## Step 7 — Load the schema

**cPanel → phpMyAdmin** → select the database → **Import** → upload `database/schema.sql` → **Go**. Repeat for `database/seed.sql`.

Or from Terminal:
```bash
cd ~/paddlerscove
mysql -u cpuser_pcapp -p cpuser_paddlers < database/schema.sql
mysql -u cpuser_pcapp -p cpuser_paddlers < database/seed.sql
```

Edit the admin email in `seed.sql` before running it, or just rely on `ADMIN_EMAILS` — either works.

---

## Step 8 — Permissions

```bash
cd ~/paddlerscove
chmod 755 public
chmod -R 755 public/assets
mkdir -p public/uploads/library storage/logs
chmod -R 775 public/uploads storage/logs
chmod 600 .env
chmod 700 config/keys
chmod 600 config/keys/* 2>/dev/null
```

---

## Step 9 — SSL

**cPanel → Security → SSL/TLS Status** → select the domain → **Run AutoSSL**

InterServer provisions a free Let's Encrypt certificate. Every OAuth provider in this project **requires HTTPS** for redirect URIs, so this isn't optional. The `.htaccess` already forces HTTPS once the cert is live.

---

## Step 10 — Email

**cPanel → Email Accounts** → Create `no-reply@paddlerscove.org`

```ini
MAIL_HOST=mail.paddlerscove.org
MAIL_PORT=587
MAIL_USER=no-reply@paddlerscove.org
MAIL_PASS=<the mailbox password>
MAIL_FROM=no-reply@paddlerscove.org
```

Then add SPF and DKIM: **cPanel → Email Deliverability** → **Repair** on the domain. Without these, your approval emails go straight to Gmail's spam folder and neighbors will assume the site is broken.

---

## Step 11 — Cron for calendar sync

**cPanel → Advanced → Cron Jobs** → Once per hour:

```
/usr/local/bin/php /home/USER/paddlerscove/bin/sync-events.php >/dev/null 2>&1
```

Verify the PHP binary path with `which php` in Terminal — on some InterServer builds it's `/opt/alt/php82/usr/bin/php`.

---

## Step 12 — Smoke test

1. `https://paddlerscove.org` → homepage renders with the logo and four cards
2. `/login` → the configured provider buttons appear
3. Sign in with your admin email → you should land on `/register/address`
4. Submit your address → you're approved automatically (admin bootstrap)
5. `/admin` → dashboard loads
6. `/library/new` → add a test item
7. `/directory` → search for your own name

---

## Backups

**cPanel → Backup Wizard** for full account backups. For the database specifically, a nightly cron:

```
0 2 * * * /usr/bin/mysqldump -u cpuser_pcapp -p'PASSWORD' cpuser_paddlers | gzip > /home/USER/backups/pc-$(date +\%F).sql.gz
```

Prune with a second job so it doesn't quietly eat your disk quota:
```
0 3 * * * find /home/USER/backups -name "pc-*.sql.gz" -mtime +30 -delete
```

---

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| 500 on every page | Missing `vendor/` or bad `.env` | Set `APP_DEBUG=true` temporarily; check `storage/logs/php-error.log` |
| Blank white page | PHP fatal with display_errors off | Same as above |
| CSS not loading | `APP_URL` wrong | Must match the actual scheme + host exactly |
| "Access denied for user" | DB user not attached to the DB | cPanel → MySQL Databases → Add User To Database → ALL PRIVILEGES |
| Redirect loop | HTTPS forced before the cert is live | Run AutoSSL first |
| Uploads fail | Directory not writable | `chmod 775 public/uploads/library` |
