# ECStores — inMotion Shared Hosting Deployment Guide

**Last updated:** 2026-06-04  
**Server:** inMotion Hosting shared plan  
**Domain:** ecstores.ca (live — addon domain on the `eastcoastwebcraft.ca` cPanel account; old `eastcoastweb.ca` test domain retired)  
**cPanel username:** n777909  

---

## Prerequisites

- cPanel access to your inMotion account
- FTP client (FileZilla) or cPanel File Manager
- PuTTY (Windows SSH client) — download from putty.org
- PuTTYgen (included with PuTTY installer) — for converting SSH keys

---

## Step 1 — Generate and Authorize an SSH Key

inMotion shared hosting **requires SSH key authentication** — password login via SSH is disabled.

1. Log into cPanel → **SSH Access** → **Manage SSH Keys**
2. Click **Generate a New Key**
   - Key name: `id_rsa` (default)
   - Leave passphrase blank (or set one you'll remember)
   - Click Generate
3. Back on Manage SSH Keys, click **Authorize** next to the key you just created
4. Click **View/Download** on the Private Key → download it
5. Open **PuTTYgen** → File → Load Private Key → select the downloaded file
6. Click **Save Private Key** → save as `inmotion_ecstores.ppk`

---

## Step 2 — Connect via SSH

Open PuTTY:

- **Host:** `eastcoastwebcraft.ca` (your PRIMARY domain — not the `ecstores.ca` addon domain)
- **Port:** `2222`
- **Connection → SSH → Auth → Credentials:** browse to your `.ppk` file
- **Username:** `n777909`

Click Open. You should land at `[n777909@ecngx364 ~]$`.

Navigate to the ECStores directory:
```bash
cd ecstores
```

---

## Step 3 — Set the PHP 8.3 Alias

The server's default `php` command is PHP 8.1. Laravel 13 requires PHP 8.3.

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

Run this every SSH session (it's not persisted). To make it permanent, add it to `~/.bashrc`:
```bash
echo "alias php83='/opt/cpanel/ea-php83/root/usr/bin/php'" >> ~/.bashrc
source ~/.bashrc
```

Verify:
```bash
php83 --version
# Should show: PHP 8.3.x
```

---

## Step 4 — Upload ECStores Files

Upload the entire ECStores project to `/home/n777909/ecstores/` via FTP or cPanel File Manager.

**Important:** The `.env` file is hidden (starts with a dot). In cPanel File Manager, enable "Show Hidden Files" in Settings. Upload `.env` separately after configuring it (see Step 5).

**Do not upload:**
- `vendor/` — will be installed via composer on the server
- `node_modules/` — not needed in production
- `bootstrap/cache/*.php` — will be generated by artisan

---

## Step 5 — Configure .env

Create/edit `/home/n777909/ecstores/.env` with these production values:

```ini
APP_NAME=ECStores
APP_ENV=production
APP_KEY=                          # Leave blank — generated in Step 7
APP_DEBUG=false
APP_URL=https://ecstores.ca

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=n777909_ecstore       # Central database (pre-create in cPanel)
DB_USERNAME=n777909_ecstore_usr   # MySQL user created in cPanel
DB_PASSWORD=your_password_here

SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=.ecstores.ca   # Leading dot is critical for subdomain sessions

BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database

MAIL_MAILER=smtp
MAIL_HOST=mail.eastcoastwebcraft.ca
MAIL_PORT=587
MAIL_USERNAME=info@eastcoastwebcraft.ca
MAIL_PASSWORD=your_mail_password
MAIL_FROM_ADDRESS=info@eastcoastwebcraft.ca
MAIL_FROM_NAME="${APP_NAME}"

STRIPE_KEY=pk_test_...
STRIPE_SECRET=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

VITE_APP_NAME="ECStores"
```

**To create the central database:**
1. cPanel → **MySQL Databases**
2. Create database: type `ecstore` → cPanel saves it as `n777909_ecstore`
3. Create user: type `ecstore_usr` → cPanel saves it as `n777909_ecstore_usr`
4. Add user to database with **ALL PRIVILEGES**

---

## Step 6 — Install Composer Dependencies

```bash
php83 /opt/cpanel/composer/bin/composer install --no-dev --optimize-autoloader 2>&1
```

This takes 2–5 minutes. You should see 100+ packages installed and end with "Successfully upgraded!" from Filament.

If you see errors about PHP version, confirm the `php83` alias is set (Step 3).

---

## Step 7 — Run Artisan Setup Commands

```bash
php83 artisan key:generate
php83 artisan migrate --force
php83 artisan config:cache
php83 artisan route:cache
php83 artisan view:cache
```

**If `migrate` fails with "Specified key was too long; max key length is 1000 bytes":**  
This is a MySQL shared hosting limitation. The fix is already in the codebase (`Schema::defaultStringLength(191)` in `AppServiceProvider` and shortened varchar columns in the Cashier migrations). If you're deploying from a clean checkout of this repo, these fixes are already applied and migration should work.

---

## Step 8 — Create Super Admin Account

```bash
php83 artisan tinker
```

Inside tinker:
```php
\App\Models\SuperAdmin::create([
    'name'     => 'Denis Gallant',
    'email'    => 'denis.gallant@gmail.com',
    'password' => 'YourStrongPasswordHere',
]);
exit
```

> **Do NOT wrap the password in `bcrypt()`** — the `hashed` cast on the model hashes it automatically. Using `bcrypt()` double-hashes and login silently fails.
>
> **To reset a forgotten password**, bypass the model cast with a raw query:
> ```php
> DB::table('super_admins')->where('email', 'denis.gallant@gmail.com')->update(['password' => bcrypt('NewPassword')]);
> ```

---

## Step 9 — Configure cPanel for Wildcard Subdomains

### 9a — Point domain to ECStores public folder

In cPanel → **Domains**:
- Find `ecstores.ca` → Manage → set Document Root to `/home/n777909/ecstores/public`

### 9b — Create wildcard subdomain

In cPanel → **Subdomains**:
- Subdomain: `*`
- Domain: `ecstores.ca`
- Document Root: `/home/n777909/ecstores/public`
- Click Create

### 9c — Install wildcard SSL certificate

In cPanel → **SSL/TLS** → Let's Encrypt (or AutoSSL):
- Issue certificate covering `*.ecstores.ca`

Verify both the wildcard subdomain and the domain itself appear as covered.

---

## Step 10 — Test

Visit `https://ecstores.ca/super`

You should see the Filament super-admin login page. Log in with the credentials from Step 8.

---

## Tenant Database Setup (Per New Customer)

Because inMotion shared hosting cannot run `CREATE DATABASE` from the app, **each tenant database must be manually created in cPanel before provisioning**.

When a new client signs up for ECStores:

1. cPanel → **MySQL Databases**
2. Create database: type the tenant slug (e.g. `harbourgifts`) → saved as `n777909_harbourgifts`
3. Add the app MySQL user (`n777909_ecstore_usr`) with **ALL PRIVILEGES**
4. In ECW admin → ECStores → retry provisioning (or create tenant in ECStores super-admin)

The app's `SharedHostingMySQLDatabaseManager` skips `CREATE DATABASE` and verifies the DB exists. If you retry provisioning before creating the DB, you get a clear error message.

**Moving to VPS later:** Change one line in `config/tenancy.php`:
```php
// FROM:
'mysql' => App\TenantDatabaseManagers\SharedHostingMySQLDatabaseManager::class,
// TO:
'mysql' => Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager::class,
```
And change the prefix from `'n777909_'` back to `'tenant_'`.

---

## Troubleshooting

### All artisan commands produce no output
**Cause:** `vendor/` directory is missing (composer install never completed).  
**Fix:** Run `ls -la vendor/` to confirm. If missing, re-run the composer install command from Step 6.

### Artisan commands produce no output even with vendor/ present
**Cause:** A corrupted bootstrap cache (config.php cached with wrong values).  
**Fix:**
```bash
rm -f bootstrap/cache/config.php bootstrap/cache/routes*.php bootstrap/cache/packages.php bootstrap/cache/services.php
```
Then retry the artisan command.

### SSH "No supported authentication methods available (server sent: publickey)"
**Cause:** Trying to use password auth, or the SSH key isn't authorized in cPanel.  
**Fix:** Generate and authorize a key in cPanel → SSH Access (see Step 1).

### SSH connection closed / "invalid format"
**Cause:** Passing a `.ppk` file to PowerShell's built-in `ssh` command. PowerShell's OpenSSH can't read PuTTY format.  
**Fix:** Use PuTTY.exe (not PowerShell's ssh), with the `.ppk` file in Connection → SSH → Auth → Credentials.

### "php83: command not found"
**Cause:** The alias wasn't set in this session.  
**Fix:** Re-run `alias php83='/opt/cpanel/ea-php83/root/usr/bin/php'`

### .env file not visible in File Manager
**Cause:** Hidden files are not shown by default.  
**Fix:** In cPanel File Manager → Settings → check "Show Hidden Files (dotfiles)".

### "SQLSTATE[42000]: Specified key was too long; max key length is 1000 bytes"
**Cause:** MySQL on shared hosting uses an older InnoDB row format with a 1000-byte index limit. utf8mb4 uses 4 bytes per character so varchar(255) primary/index keys = 1020 bytes.  
**Fix:** Already applied in this codebase. If it reappears on a fresh install, check:
- `AppServiceProvider::boot()` has `Schema::defaultStringLength(191)`
- The subscriptions migration has `string('user_id', 36)` and `string('stripe_status', 191)`
- The subscription_items migration has `string('stripe_price', 191)`
