# 🚀 TemseeEdu — Plesk Deployment Guide

> **Stack:** Laravel 11 · PHP 8.3+ · MySQL · Redis · Stancl Tenancy (subdomain-based)

---

## 1. Server Requirements (Plesk Panel)

Confirm these are enabled in **Plesk → PHP Settings** for your domain:

| Requirement | Value |
|---|---|
| PHP version | **8.3** or **8.4** |
| Extensions | `pdo_mysql`, `mbstring`, `openssl`, `bcmath`, `gd`, `zip`, `redis`, `intl`, `fileinfo`, `sodium` |
| `memory_limit` | `256M` minimum |
| `max_execution_time` | `120` |
| `upload_max_filesize` | `50M` |
| `post_max_size` | `50M` |

---

## 2. Domain & Wildcard Subdomain Setup

TemseeEdu uses subdomain-based tenancy (`school.yourdomain.com`).

### In Plesk:
1. Go to **Domains → yourdomain.com → DNS Settings**
2. Add a wildcard A record:
   ```
   Type: A
   Host: *
   Points to: <your server IP>
   ```
3. Add root A record if not already there:
   ```
   Type: A
   Host: @
   Points to: <your server IP>
   ```

### SSL Wildcard Certificate:
1. In Plesk go to **SSL/TLS Certificates**
2. Use **Let's Encrypt** → tick **"Wildcard domain"** (requires DNS challenge)
3. Or upload your own wildcard `*.yourdomain.com` certificate

---

## 3. Create the Main Domain in Plesk

1. **Plesk → Add Domain** → set `yourdomain.com`
2. Set **Document Root** to: `public_html/public` (or your web root)
3. Enable **PHP-FPM** mode (not CGI)

---

## 4. Upload the Application

### Option A — Git deploy (recommended):
```bash
# SSH into server
ssh user@yourserver.com

cd /var/www/vhosts/yourdomain.com/

# Clone into httpdocs (rename public to public_html after)
git clone https://your-repo-url.git httpdocs
```

### Option B — FTP/SFTP upload:
Upload the entire project folder to `httpdocs/` on the server.

> ⚠️ Make sure the **`public/`** directory is the web root (document root in Plesk).

---

## 5. Configure the Document Root

In **Plesk → Hosting Settings** for your domain:
- Set **Document root** to: `httpdocs/public`

Or in Apache/Nginx config (Plesk Additional Config):
```nginx
root /var/www/vhosts/yourdomain.com/httpdocs/public;
```

---

## 6. Install PHP Dependencies

```bash
cd /var/www/vhosts/yourdomain.com/httpdocs

# Install Composer dependencies (no dev)
composer install --optimize-autoloader --no-dev
```

---

## 7. Configure Environment

```bash
cp .env.example .env
nano .env
```

Set these critical values:

```dotenv
APP_NAME="TemseeEdu"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com

# Database (central DB)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=temsee_central
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password

# Tenant DB prefix (each school gets: temsee_tenant_schoolname)
TENANCY_DB_PREFIX=temsee_tenant_

# Redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

# Paystack (LIVE keys)
PAYSTACK_PUBLIC_KEY=pk_live_xxxxxxxxxx
PAYSTACK_SECRET_KEY=sk_live_xxxxxxxxxx
PAYSTACK_WEBHOOK_SECRET=sk_live_xxxxxxxxxx

# Mail (SMTP)
MAIL_MAILER=smtp
MAIL_HOST=smtp.yourprovider.com
MAIL_PORT=587
MAIL_USERNAME=noreply@yourdomain.com
MAIL_PASSWORD=your_mail_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="TemseeEdu"
```

---

## 8. Generate Keys & Run Migrations

```bash
# Generate app key
php artisan key:generate

# Run central database migrations
php artisan migrate --force

# Run migrations for all existing tenant schools
php artisan tenants:migrate --force

# Link storage
php artisan storage:link

# Seed central data (if needed)
php artisan db:seed --force
```

---

## 9. Build Frontend Assets

```bash
# Install Node dependencies
npm install

# Build for production
npm run build
```

> This generates the `public/build/` directory with compiled CSS/JS.

---

## 10. Set Permissions

```bash
chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache
# (Plesk may use different user — check with: ps aux | grep php)
```

---

## 11. Optimize for Production

```bash
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan filament:cache-components
```

---

## 12. Queue Worker (for background jobs)

### In Plesk — Scheduled Tasks (Cron):

Add one cron job:
```
* * * * * cd /var/www/vhosts/yourdomain.com/httpdocs && php artisan schedule:run >> /dev/null 2>&1
```

### Queue Worker — Plesk Supervisor or SSH persistent:

Plesk may not have Supervisor. Use one of:

**Option A — Plesk Scheduled Task (polling, every minute):**
```
* * * * * cd /var/www/vhosts/yourdomain.com/httpdocs && php artisan queue:work --max-time=55 --stop-when-empty redis 2>&1
```

**Option B — SSH keep-alive (if server allows):**
```bash
nohup php artisan queue:work redis --timeout=90 --tries=3 &
```

**Option C — Supervisor (if available on server):**
```ini
[program:temsee-worker]
command=php /var/www/vhosts/yourdomain.com/httpdocs/artisan queue:work redis --timeout=90 --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/vhosts/yourdomain.com/logs/worker.log
```

---

## 13. Configure Plesk Nginx (Additional Directives)

Go to **Plesk → Domain → Apache & Nginx Settings → Additional Nginx Directives**:

```nginx
# Allow large uploads
client_max_body_size 50M;

# Cache static assets
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

# Prevent direct access to sensitive files
location ~ /\.(?!well-known) {
    deny all;
}
```

---

## 14. Paystack Webhook Registration

In **Paystack Dashboard → Settings → API Keys & Webhooks**:

- **Webhook URL:** `https://yourdomain.com/paystack/webhook`
- **Events to enable:** `charge.success`, `charge.failed`, `subscription.disable`, `subscription.not_renew`

---

## 15. Post-Deploy Checklist

- [ ] Visit `https://yourdomain.com` — homepage loads
- [ ] Visit `https://yourdomain.com/admin` — admin panel loads
- [ ] Create a test school via the registration page
- [ ] Confirm `https://testschool.yourdomain.com/admin` loads
- [ ] Make a test Paystack payment (use live keys, small amount)
- [ ] Confirm webhook fires (`charge.success`) → tenant created
- [ ] Check `storage/logs/laravel.log` for errors
- [ ] Verify wildcard SSL covers `*.yourdomain.com`

---

## 16. Deploying Updates (Zero-Downtime)

```bash
cd /var/www/vhosts/yourdomain.com/httpdocs

git pull origin main

composer install --optimize-autoloader --no-dev
npm run build

php artisan migrate --force
php artisan tenants:migrate --force

php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan filament:cache-components

# Restart queue workers
php artisan queue:restart
```

---

## Common Issues

| Problem | Fix |
|---|---|
| 500 error after deploy | Check `storage/logs/laravel.log`; run `php artisan config:clear` |
| Subdomain not loading | Check wildcard DNS A record; check Plesk has wildcard SSL |
| Storage files not showing | Run `php artisan storage:link` |
| Queued jobs not running | Restart queue worker; confirm Redis is running |
| `Class not found` errors | Run `composer dump-autoload` |
| Tenancy migration fails | Check DB user has `CREATE DATABASE` privilege |



php artisan temsee:provision-school \
  --tenant-id=amezion \
  --domain=ame.edu.uptimacredit.com \
  --name="AMEZ SHS School" \
  --email=wisdak7@gmail.com.com \
  --plan=school_edition \
  --years=1


  https://edu.uptimacredit.com