# CC Soccer D11 - Deployment Guide

This guide covers server setup, deployment, and ongoing operations for the CC Soccer Drupal 11 site on InMotion Hosting.

For **local development setup**, see `INSTALLATION_GUIDE.md`.

---

## Table of Contents

1. [Server Environment](#server-environment)
2. [SSH Setup](#ssh-setup)
3. [Server Directory Structure](#server-directory-structure)
4. [Initial Test Site Deployment](#initial-test-site-deployment)
5. [Initial Production Deployment](#initial-production-deployment)
6. [Development Workflow & Architecture](#development-workflow--architecture)
7. [Routine Deployment (Post Go-Live)](#routine-deployment-post-go-live)
8. [Database Operations](#database-operations)
9. [Settings Files](#settings-files)
10. [Security](#security)
11. [Troubleshooting](#troubleshooting)

---

## 1. Server Environment

### Hosting

- **Provider:** InMotion Hosting (Shared)
- **Control Panel:** cPanel
- **MariaDB:** 10.6.24 (meets D11 requirement of 10.6+)
- **PHP:** 8.3 (set per subdomain in MultiPHP Manager)
- **Composer:** Pre-installed on shared hosting
- **SSH:** Available on port 2222

### Domains

| Domain | Purpose | PHP | Database |
|--------|---------|-----|----------|
| `ccsoccer.com` | Production D7 site (legacy) | 7.1 | `n6ac4b5_ccsoccer` |
| `test.ccsoccer.com` | D11 test/staging site | 8.3 | TBD — see [Database Setup](#43-create-database) |
| `ccsoccer.com` (future) | D11 production site | 8.3 | TBD |

### Account Details

- **cPanel Username:** `n6ac4b5` (prefix for all DB names/users)
- **Server:** See cPanel left sidebar for hostname
- **GitHub Repo:** `https://github.com/caleb-ccsoccer/ccsoccer-d11.git`

---

## 2. SSH Setup

### 2.1 Current Setup (Caleb's Mac — already configured)

Caleb's SSH is fully set up. Key pair lives at `~/.ssh/id_rsa` / `~/.ssh/id_rsa.pub`.
The key is authorized in cPanel. `~/.ssh/config` has the following entry:

```
Host ccsoccer
    User n6ac4b5
    Hostname 144.208.71.134
    Port 2222
    IdentityFile ~/.ssh/id_rsa
```

Connect with just:

```bash
ssh ccsoccer
```

The connection shows a post-quantum key exchange warning from OpenSSH — ignore it, it's informational only.

**Caleb is the gatekeeper for server access.** Andrew does not currently have SSH access and doesn't need it for normal dev work.

---

### 2.2 Setting Up SSH for a New Developer (Andrew or others — when needed)

If a second developer ever needs SSH access:

**On their Mac:**
1. Check for existing key: `ls ~/.ssh/` — look for `id_rsa`, `id_ed25519`, or similar
2. If no key exists, generate one: `ssh-keygen -t ed25519 -C "their-email@example.com"`
3. Copy their public key: `cat ~/.ssh/id_ed25519.pub` (or `id_rsa.pub`)

**In cPanel (Caleb does this):**
1. Log into cPanel → Security → SSH Access → Manage SSH Keys
2. Click **Import Key**
3. Paste their public key, give it a name (e.g. `andrew_key`)
4. Back on Manage SSH Keys, click **Authorize** next to the new key

**On their Mac — add SSH config entry:**
```
Host ccsoccer
    User n6ac4b5
    Hostname 144.208.71.134
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
```

Test: `ssh ccsoccer`

---

### 2.3 Verify Server Tools

Once connected via SSH, confirm what's available:

```bash
# Check PHP version
php -v

# Check Composer
composer --version

# Check git
git --version

# Check MariaDB access
mysql --version
```

**If PHP version is wrong on CLI:** The command-line PHP may differ from the web PHP version. Use the versioned path:

```bash
/opt/cpanel/ea-php83/root/usr/bin/php -v
```

You may need to alias this:

```bash
alias php=/opt/cpanel/ea-php83/root/usr/bin/php
```

Add to `~/.bashrc` to make it permanent.

---

## 3. Server Directory Structure

### Layout

```
/home/n6ac4b5/
├── public_html/
│   ├── ccsoccer_site/             # Live D7 site (ccsoccer.com) — DO NOT TOUCH
│   │   └── sites/default/
│   │       └── settings.php       # D7 DB credentials live here
│   ├── slofriendly_site/          # SLO Friendly D7 site
│   └── test_ccsoccer_site/        # D11 test site (test.ccsoccer.com)
│       ├── composer.json
│       ├── composer.lock
│       ├── config/
│       │   └── sync/
│       ├── vendor/
│       └── web/                   # ← Document root points HERE
│           ├── .htaccess          # Protected via git skip-worktree (IP whitelist)
│           ├── index.php
│           └── sites/
│               └── default/
│                   ├── settings.php
│                   └── settings.local.php  # Server-specific (not in git)
└── (future) d11-production-ready.sql.gz   # Uploaded migration DB export
```

### Document Root Configuration

**Critical:** The subdomain document root must point to the `web/` directory inside the project, not the project root.

In cPanel:
1. Go to **Domains** (or **Subdomains** in older cPanel)
2. Find `test.ccsoccer.com`
3. Edit the **Document Root** to: `/home/n6ac4b5/ccsoccer-d11/web`

If cPanel doesn't allow pointing a subdomain outside its default directory, you have two alternatives:

**Alternative A:** Clone the repo directly into the subdomain directory:
```
/home/n6ac4b5/test.ccsoccer.com/   # Project root here
└── web/                             # Set document root to this
```

**Alternative B:** Symlink:
```bash
rm -rf ~/test.ccsoccer.com
ln -s ~/ccsoccer-d11/web ~/test.ccsoccer.com
```

Test which approach works with your cPanel setup.

---

## 4. Initial Test Site Deployment

### 4.1 Prerequisites

- [ ] SSH access working (Section 2)
- [ ] PHP 8.3 set for test.ccsoccer.com in MultiPHP Manager
- [ ] Database created (Section 4.3)
- [ ] Backup/move existing test site contents

### 4.2 Back Up Existing Test Site

```bash
ssh inmotion
cd ~
# Zip whatever's currently in the test subdomain directory
tar -czf test_backup_$(date +%Y-%m-%d).tar.gz test.ccsoccer.com/
```

### 4.3 Create Database

In cPanel:
1. Go to **MySQL Databases**
2. Create new database (will be prefixed, e.g., `n6ac4b5_d11test`)
3. Create a database user (or use existing) with a strong password
4. Add user to the database with **All Privileges**
5. Note the full database name, username, and password for settings.local.php

### 4.4 Clone the Repository

```bash
ssh inmotion
cd ~
git clone https://github.com/caleb-ccsoccer/ccsoccer-d11.git
cd ccsoccer-d11
```

### 4.5 Install Dependencies

```bash
composer install --no-dev
```

`--no-dev` skips development-only packages (like Devel). If you want Devel on the test site for debugging, omit the flag.

**If Composer runs out of memory:**

```bash
php -d memory_limit=-1 /usr/local/bin/composer install --no-dev
```

### 4.6 Point Document Root

Update test.ccsoccer.com's document root to the `web/` directory (see Section 3).

### 4.7 Create settings.local.php

Create `/home/n6ac4b5/ccsoccer-d11/web/sites/default/settings.local.php`:

```php
<?php

/**
 * CCSoccer D11 - Test Environment Settings
 * This file is NOT in git. Each environment has its own copy.
 */

// Database connection.
$databases['default']['default'] = [
  'database' => 'n6ac4b5_d11test',
  'username' => 'n6ac4b5_d11user',
  'password' => 'YOUR_DB_PASSWORD_HERE',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
  'prefix' => '',
  'collation' => 'utf8mb4_general_ci',
];

// Hash salt — generate a unique one or use the DDEV one for test.
$settings['hash_salt'] = 'GENERATE_A_RANDOM_STRING_HERE';

// Trusted hosts.
$settings['trusted_host_patterns'] = [
  '^test\.ccsoccer\.com$',
];

// File paths.
$settings['file_private_path'] = '/home/n6ac4b5/private_files/test';

// Config sync directory (should match settings.php).
$settings['config_sync_directory'] = '../config/sync';

// Dev mode — show dev banner on test site.
$settings['dev_mode'] = TRUE;

// Clickatell SMS credentials.
// For test site: use real creds but keep dev_override_phone to prevent real SMS.
$config['ccsoccer.notifications']['clickatell_user'] = 'ccsoccer';
$config['ccsoccer.notifications']['clickatell_password'] = 'YOUR_CLICKATELL_PASSWORD';
$config['ccsoccer.notifications']['clickatell_api_id'] = '3570124';
$config['ccsoccer.notifications']['clickatell_from'] = '12035909698';
$config['ccsoccer.notifications']['dev_override_phone'] = '19163008466';

// Authorize.net — use SANDBOX credentials for test site.
// $config['commerce_payment.commerce_payment_gateway.authorize_net']['...'] = '...';

// SMTP / Email — configure for test site.
// Option A: InMotion's mail server
// Option B: External service (SendGrid, Mailgun, etc.)
// Option C: Leave unconfigured — emails will fail silently or use PHP mail()
```

**To generate a hash salt:**

```bash
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;"
```

### 4.8 Import Database

**Option A: Import the migrated 200-user database from local DDEV**

On your Mac:
```bash
cd ~/Sites/ccsoccer-d11

# Export from DDEV
ddev export-db --gzip --file=d11-test-export.sql.gz

# Upload to server
scp -P 2222 -i ~/.ssh/inmotion_key d11-test-export.sql.gz n6ac4b5@ccsoccer.com:~/
```

On the server:
```bash
gunzip d11-test-export.sql.gz
mysql -u n6ac4b5_d11user -p n6ac4b5_d11test < d11-test-export.sql
```

**Option B: Fresh install on the server**

```bash
cd ~/ccsoccer-d11

# Install Drupal
php vendor/bin/drush site:install standard \
  --site-name="CC Soccer D11 - TEST" \
  --account-name=admin \
  --account-pass=PICK_A_PASSWORD \
  -y

# Fix UUID and import config
php vendor/bin/drush config:set system.site uuid $(grep uuid config/sync/system.site.yml | awk '{print $2}') -y
php vendor/bin/drush entity:delete shortcut_set default -y
php vendor/bin/drush cim -y
php vendor/bin/drush updb -y
php vendor/bin/drush cr
```

**Note:** On the server, use `php vendor/bin/drush` instead of `ddev drush`. If that doesn't work, try the full PHP path: `/opt/cpanel/ea-php83/root/usr/bin/php vendor/bin/drush`.

### 4.9 Set File Permissions

```bash
cd ~/ccsoccer-d11/web

# Writable files directory
chmod -R 755 sites/default/files
mkdir -p sites/default/files/translations
chmod -R 775 sites/default/files

# Protect settings files
chmod 444 sites/default/settings.php
chmod 440 sites/default/settings.local.php
```

### 4.10 Verify

1. Visit `https://test.ccsoccer.com` — should see the Drupal site
2. Log in with admin credentials
3. Check `/admin/reports/status` for any warnings
4. Test a few pages to make sure entities load

---

## 5. Initial Production Deployment

> **TODO:** Fill in before go-live. Largely mirrors Section 4 with these differences:

### Key Differences from Test

| Setting | Test | Production |
|---------|------|------------|
| `$settings['dev_mode']` | `TRUE` | `FALSE` or remove |
| Trusted hosts | `test.ccsoccer.com` | `ccsoccer.com`, `www.ccsoccer.com` |
| Database | `n6ac4b5_d11test` | `n6ac4b5_d11prod` (or similar) |
| Authorize.net | Sandbox credentials | **Live** credentials |
| Clickatell | `dev_override_phone` set | Remove override — real SMS to real users |
| SMTP | Optional | Required — real emails to real users |
| HTTP Auth | Yes (.htpasswd) | No |
| Composer | `--no-dev` | `--no-dev` |
| Error display | Verbose | Hide errors from users |

### Production Checklist

- [ ] Remove dev banner (`dev_mode = FALSE`)
- [ ] Live Authorize.net gateway credentials
- [ ] Live Clickatell credentials (no dev_override_phone)
- [ ] SMTP configured for real email delivery
- [ ] HTTP auth removed
- [ ] `$config['system.logging']['error_level'] = 'hide';`
- [ ] Cron configured (cPanel Cron Jobs → run every 15-30 min)
- [ ] SSL certificate active
- [ ] Backup strategy in place
- [ ] DNS cutover plan (switch ccsoccer.com from D7 to D11)
- [ ] D7 site backed up and archived

---

## 6. Development Workflow & Architecture

### How Code Flows

```
┌─────────────┐      ┌──────────┐      ┌───────────────┐
│ Caleb/Andrew│      │  GitHub  │      │ InMotion      │
│ Local DDEV  │─push→│   main   │      │ test/prod     │
│             │←pull─│          │      │               │
└─────────────┘      └──────────┘      └───────────────┘
                                              │
                                        SSH in, then:
                                        git pull
                                        composer install
                                        drush updb
                                        drush cim
                                        drush cr
```

### Branching Strategy

- **`main`** — stable, deployable code. Both Caleb and Andrew work here for most changes.
- **Feature branches** — for bigger or experimental work (e.g., `feature/tournament-overhaul`). Merge to main when ready.
- **No `develop` branch** — unnecessary overhead for a two-person team.
- **Tag releases** when deploying to production: `v1.0`, `v1.1`, etc.

### Config Management Between Developers

Drupal config lives in `config/sync/` and is tracked in git. The workflow:

1. Make config changes in the Drupal admin UI (locally in DDEV)
2. Export: `ddev drush cex -y`
3. Review: `git diff config/sync/`
4. Commit and push to GitHub
5. Other developer pulls, then imports: `ddev drush cim -y`
6. On server: `git pull` then `drush cim -y`

**Important:** Config import/export requires that all environments share the same site UUID. Since we're importing a database dump to the test server, this is handled automatically.

### Daily Workflow

**Before starting work:**
```bash
cd ~/Sites/ccsoccer-d11
git pull
ddev drush cim -y
ddev drush updb -y
ddev drush cr
```

**After making changes:**
```bash
# If you changed config in the admin UI:
ddev drush cex -y

git add -A
git commit -m "Descriptive message"
git pull   # ← Always pull before push! Andrew may have pushed.
git push
```

### Working with Andrew

- Always `git pull` before `git push`
- If both editing the same file, coordinate via Slack/text
- Config conflicts: review the YAML diffs carefully — most are additive and merge cleanly
- If you get a merge conflict in config, resolve it and re-run `ddev drush cim -y` to validate

---

## 7. Routine Deployment (Post Go-Live)

### Manual Deploy Steps

```bash
ssh inmotion
cd ~/ccsoccer-d11

# Pull latest code
git pull

# Install any new/updated dependencies
composer install --no-dev

# Run database updates
php vendor/bin/drush updb -y

# Import config changes
php vendor/bin/drush cim -y

# Clear caches
php vendor/bin/drush cr
```

### Deploy Script (Optional)

Create `~/deploy-test.sh` on the server:

```bash
#!/bin/bash
# Deploy to test.ccsoccer.com
set -e

echo "=== Deploying to TEST ==="
cd ~/ccsoccer-d11

echo "Pulling latest code..."
git pull

echo "Installing dependencies..."
composer install --no-dev

echo "Running database updates..."
php vendor/bin/drush updb -y

echo "Importing config..."
php vendor/bin/drush cim -y

echo "Clearing caches..."
php vendor/bin/drush cr

echo "=== Deploy complete ==="
php vendor/bin/drush status --field=site
```

```bash
chmod +x ~/deploy-test.sh
```

Then deploy with just:

```bash
ssh inmotion
~/deploy-test.sh
```

### When to Deploy What

| Change Type | Steps Needed |
|------------|-------------|
| PHP code changes (controllers, services, forms) | `git pull` → `drush cr` |
| New/updated module via Composer | `git pull` → `composer install` → `drush updb` → `drush cr` |
| Config changes (views, permissions, fields) | `git pull` → `drush cim` → `drush cr` |
| Database schema changes (update hooks) | `git pull` → `drush updb` → `drush cr` |
| All of the above (safest) | Full deploy script |

### Environment Safety Model

The site is designed so that **config in git always defaults to safe/sandbox values**. Dangerous "live" settings only exist in `settings.local.php` on the production server, which is never committed to git. This means routine deploys (`git pull` → `drush cim`) can never accidentally flip payments, SMS, or email to production mode.

Here's how each external service is governed:

**Payments (Authorize.net)**

The payment gateway config YAML (`commerce_payment.commerce_payment_gateway.authorize_net_test.yml`) is committed to git with `mode: test` and sandbox API credentials baked in. Every `drush cim` on every environment resets the gateway to sandbox. Live credentials only exist as `$config` overrides in the production server's `settings.local.php` — they're never in git, never in config YAML, and can't be accidentally deployed anywhere.

```php
// Production settings.local.php ONLY:
$config['commerce_payment.commerce_payment_gateway.authorize_net_test']['configuration']['mode'] = 'live';
$config['commerce_payment.commerce_payment_gateway.authorize_net_test']['configuration']['api_login'] = 'LIVE_API_LOGIN';
$config['commerce_payment.commerce_payment_gateway.authorize_net_test']['configuration']['transaction_key'] = 'LIVE_TRANSACTION_KEY';
$config['commerce_payment.commerce_payment_gateway.authorize_net_test']['configuration']['client_key'] = 'LIVE_CLIENT_KEY';
```

`settings.local.php` overrides always win over config YAML, so even after a `drush cim` resets the YAML to sandbox, the production overrides re-apply on the next page load. No manual toggling needed.

**SMS (Clickatell)**

Clickatell credentials are not in config YAML at all — they only exist in `settings.local.php` per environment. On local and test, `dev_override_phone` is set so all SMS routes to a developer's phone. On production, the override is removed and SMS goes to real users. The notification service checks for the override before sending.

**Email**

Local DDEV uses Mailpit (auto-captured, nothing leaves the machine). Test and production use whatever SMTP is configured in their respective `settings.local.php`. For the test site, options include leaving it unconfigured (emails fail silently), using a service like Mailtrap to capture all outbound mail in a web UI, or adding a `dev_override_email` to redirect all mail to a developer address.

**Summary: What protects each environment**

| Service | What makes it safe | What makes it live |
|---------|-------------------|--------------------|
| Payments | Config YAML = sandbox mode + sandbox creds | Production `settings.local.php` overrides to live mode + live creds |
| SMS | `dev_override_phone` in `settings.local.php` | Remove `dev_override_phone` on production only |
| Email | Mailpit (local) or no SMTP configured (test) | SMTP configured on production only |
| Dev banner | `$settings['dev_mode'] = TRUE` | Set to `FALSE` on production only |

The key principle: **git pull + drush cim can never break production safety**. Live credentials and live behavior are exclusively controlled by `settings.local.php` on the production server.

---

## 8. Database Operations

### Backup Before Deploy

**Always back up the database before deploying updates.**

**Via Drush (SSH):**
```bash
cd ~/ccsoccer-d11
php vendor/bin/drush sql-dump --gzip --result-file=~/backups/d11-test-$(date +%Y%m%d-%H%M).sql
```

**Via phpMyAdmin:**
1. cPanel → phpMyAdmin
2. Select the database
3. Export tab → Quick → Go

**Via Backup & Migrate module:**
1. Go to `/admin/config/development/backup_migrate`
2. Click "Backup now"
3. Download the backup file

### Restore from Backup

```bash
gunzip ~/backups/d11-test-YYYYMMDD-HHMM.sql.gz
mysql -u n6ac4b5_d11user -p n6ac4b5_d11test < ~/backups/d11-test-YYYYMMDD-HHMM.sql
php vendor/bin/drush cr
```

### Import Local Database to Server

On your Mac:
```bash
ddev export-db --gzip --file=d11-export.sql.gz
scp -P 2222 -i ~/.ssh/inmotion_key d11-export.sql.gz n6ac4b5@ccsoccer.com:~/
```

On the server:
```bash
gunzip d11-export.sql.gz
mysql -u n6ac4b5_d11user -p n6ac4b5_d11test < d11-export.sql
php vendor/bin/drush cr
```

### Create Backup Directory

```bash
ssh inmotion
mkdir -p ~/backups
```

---

## 9. Settings Files

### File Hierarchy

```
settings.php          ← In git. Shared across all environments.
                         Loads settings.ddev.php (local) or settings.local.php (server).

settings.ddev.php     ← Auto-generated by DDEV. Not in git. Local dev only.
                         Sets DB to DDEV container, enables Mailpit, verbose errors.

settings.local.php    ← NOT in git. Per-environment overrides.
                         Local: Clickatell creds, dev overrides, D7 migration DB.
                         Server: DB creds, hash salt, trusted hosts, payment gateway, SMTP.
```

### What Goes in settings.local.php (Per Environment)

| Setting | Local DDEV | Test Server | Production Server |
|---------|-----------|-------------|-------------------|
| Database | Handled by settings.ddev.php | InMotion DB creds | InMotion DB creds |
| Hash salt | Handled by settings.ddev.php | Generate unique | Generate unique |
| Trusted hosts | `.*` (DDEV default) | `test.ccsoccer.com` | `ccsoccer.com`, `www.ccsoccer.com` |
| Dev mode | `TRUE` | `TRUE` | `FALSE` |
| Clickatell | Real creds + dev_override_phone | Real creds + dev_override_phone | Real creds, NO override |
| Authorize.net | Sandbox | Sandbox | **Live credentials** |
| Email | Mailpit (DDEV) | PHP mail or SMTP | SMTP configured |
| Error level | Verbose (DDEV) | Verbose | Hide |
| D7 migration DB | Secondary connection | Not needed | Not needed |

### .gitignore Protections

These files are already excluded from git via `web/sites/default/.gitignore`:

- `settings.local.php`
- `settings.ddev.php`

**Never commit credentials to git.**

---

## 10. Security

### HTTP Auth on Test Site

Protect the test site from public access with HTTP Basic Auth.

**Option A: cPanel Directory Privacy**
1. cPanel → **Directory Privacy**
2. Navigate to the test site's web directory
3. Enable password protection
4. Create a user/password

**Option B: Manual .htpasswd**

Create the password file:
```bash
# On the server
htpasswd -c ~/.htpasswd ccsoccer
# Enter a password when prompted
```

Add to the top of `~/ccsoccer-d11/web/.htaccess` (or create a separate `.htaccess` at the document root level):

```apache
# HTTP Auth — remove this block for production
AuthType Basic
AuthName "CC Soccer Test Site"
AuthUserFile /home/n6ac4b5/.htpasswd
Require valid-user
```

**Important:** Remove or comment out the HTTP auth block before deploying to production.

### Trusted Host Patterns

Always set `trusted_host_patterns` in `settings.local.php` to prevent HTTP host header attacks:

```php
// Test
$settings['trusted_host_patterns'] = [
  '^test\.ccsoccer\.com$',
];

// Production
$settings['trusted_host_patterns'] = [
  '^ccsoccer\.com$',
  '^www\.ccsoccer\.com$',
];
```

### File Permissions

```bash
# Settings files should be read-only
chmod 444 web/sites/default/settings.php
chmod 440 web/sites/default/settings.local.php

# Files directory needs to be writable
chmod -R 775 web/sites/default/files

# Private files directory (outside web root)
mkdir -p ~/private_files/test
chmod 750 ~/private_files/test
```

### update.php Access

In `settings.php`, ensure:
```php
$settings['update_free_access'] = FALSE;
```

This requires an admin login to run update.php. Never set this to TRUE on a public server.

### Production Security Checklist

- [ ] HTTP auth removed (only needed on test)
- [ ] `trusted_host_patterns` set
- [ ] `update_free_access` = FALSE
- [ ] `settings.local.php` has restrictive permissions (440)
- [ ] Error display set to hide: `$config['system.logging']['error_level'] = 'hide';`
- [ ] Dev tools (Devel, Webprofiler) disabled on production
- [ ] `$settings['dev_mode'] = FALSE;`
- [ ] SSL certificate active and HTTPS enforced
- [ ] Cron secret key configured (don't use public cron URL)
- [ ] Admin password is strong
- [ ] Private files directory is outside web root

---

## 11. Troubleshooting

### PHP CLI Version Mismatch

**Symptom:** `php -v` shows an old version (e.g., 7.4) even though MultiPHP Manager is set to 8.3.

**Cause:** MultiPHP Manager controls the web server PHP. The CLI uses the system default.

**Fix:**
```bash
# Use the versioned binary directly
/opt/cpanel/ea-php83/root/usr/bin/php -v

# Create an alias
echo 'alias php=/opt/cpanel/ea-php83/root/usr/bin/php' >> ~/.bashrc
source ~/.bashrc

# Verify
php -v
```

### Composer Out of Memory

**Symptom:** `Composer install` fails with "Allowed memory size of X bytes exhausted."

**Fix:**
```bash
php -d memory_limit=-1 /usr/local/bin/composer install --no-dev
```

Or with the versioned PHP:
```bash
/opt/cpanel/ea-php83/root/usr/bin/php -d memory_limit=-1 /usr/local/bin/composer install --no-dev
```

### Drush Not Found

**Symptom:** `drush` command not found after git clone + composer install.

**Fix:** Drush is installed in `vendor/bin/`. Use the full path:
```bash
php vendor/bin/drush cr
```

Or create an alias:
```bash
echo 'alias drush="php ~/ccsoccer-d11/vendor/bin/drush"' >> ~/.bashrc
source ~/.bashrc
```

### White Screen of Death

**Symptom:** Blank white page, no error message.

**Debug:**
1. Check PHP error log: `tail -f ~/logs/error.log` (path may vary)
2. Or check via cPanel → **Errors** or **Metrics → Errors**
3. Temporarily enable verbose errors in settings.local.php:
   ```php
   $config['system.logging']['error_level'] = 'verbose';
   ```
4. Check file permissions on `sites/default/files`

### CSS/JS Not Loading

**Symptom:** Site loads but looks unstyled.

**Cause:** Usually a document root or .htaccess issue — clean URLs / rewrite rules not working.

**Fix:**
1. Verify document root points to `web/` directory
2. Verify `.htaccess` is present in `web/`
3. Verify Apache mod_rewrite is enabled (should be on InMotion)
4. Check: `php vendor/bin/drush cr`

### Config Import Fails on Server

**Symptom:** `drush cim` fails with errors about missing modules or config entities.

**Fix:**
```bash
# Make sure all composer dependencies are installed
composer install --no-dev

# Run database updates first (may add required schema)
php vendor/bin/drush updb -y

# Then try config import again
php vendor/bin/drush cim -y
```

### File Upload / Permission Errors

**Symptom:** Can't upload files, or Drupal reports file permission issues.

**Fix:**
```bash
# Ensure files directory exists and is writable
mkdir -p web/sites/default/files
chmod -R 775 web/sites/default/files

# Ensure translations directory exists
mkdir -p web/sites/default/files/translations
chmod 775 web/sites/default/files/translations
```

### Cron Not Running

**Setup cron in cPanel:**
1. cPanel → **Cron Jobs**
2. Add a new cron job, every 15 or 30 minutes:
   ```
   cd /home/n6ac4b5/ccsoccer-d11 && /opt/cpanel/ea-php83/root/usr/bin/php vendor/bin/drush cron
   ```
3. Or use Drupal's cron URL with a secret key (find at `/admin/config/system/cron`)

---

## Appendix: Quick Reference Commands

### SSH In

```bash
ssh inmotion
# or: ssh -p 2222 -i ~/.ssh/inmotion_key n6ac4b5@ccsoccer.com
```

### Deploy to Test

```bash
ssh inmotion
cd ~/ccsoccer-d11
git pull
composer install --no-dev
php vendor/bin/drush updb -y
php vendor/bin/drush cim -y
php vendor/bin/drush cr
```

### Upload DB from Local

```bash
# On Mac
ddev export-db --gzip --file=d11-export.sql.gz
scp -P 2222 -i ~/.ssh/inmotion_key d11-export.sql.gz n6ac4b5@ccsoccer.com:~/

# On server
gunzip d11-export.sql.gz
mysql -u n6ac4b5_d11user -p n6ac4b5_d11test < d11-export.sql
php vendor/bin/drush cr
```

### Backup DB on Server

```bash
cd ~/ccsoccer-d11
php vendor/bin/drush sql-dump --gzip --result-file=~/backups/d11-$(date +%Y%m%d-%H%M).sql
```

---

**Last Updated:** February 16, 2026
