# Pacific Logistics — Namecheap Shared Hosting Deploy Checklist

Target environment: **Namecheap Stellar / Stellar Plus / Stellar Business** shared plan,
PHP 8.1+, MySQL 8, cPanel, PositiveSSL cert (bundled with the plan).

This file is the operator's cheat sheet for a green-field deploy. Follow it top-to-bottom.

---

## 1 · Pre-flight

| Check | How | Why |
|---|---|---|
| PHP ≥ 8.1 | cPanel → Select PHP Version | Match-arms, enums, `hash_equals`, JSON functions used throughout |
| PHP extensions | Ensure `pdo_mysql`, `mbstring`, `openssl`, `curl`, `fileinfo`, `json`, `gd` are ticked | Beem API needs `curl`; file uploads sniff MIME via `fileinfo`; images resize via `gd` |
| MySQL 8 database | cPanel → MySQL Databases → create `pacificlg_prod` (or similar) + user + grant ALL | JSON columns require MySQL 5.7+, we assume 8 |
| SSL cert active | cPanel → SSL/TLS Status → AutoSSL run | GPS webhook token flows over URL query — MUST be HTTPS-only |
| Cron enabled | cPanel → Advanced → Cron Jobs (Stellar: 100 jobs allowed) | Alerts engine + outbox dispatch run on 5-min tick |

---

## 2 · Files & DB

```bash
# 1. Upload via SFTP or cPanel File Manager to public_html/pacific/
#    (or wherever the client-visible root will live)

# 2. Ensure these dirs are writable (chmod 775):
#      uploads/     attachments/     logs/     backups/

# 3. Import DB slices IN ORDER (via cPanel phpMyAdmin OR shell):
```

Order of SQL imports (idempotent — safe to re-run):

```
db/pacific_00_seed.sql              (users, roles, tenants — from rsflow base)
db/pacific_01_trucks.sql
db/pacific_02_drivers.sql
db/pacific_03_customers.sql
db/pacific_04_routes.sql
db/pacific_05_trip_requests.sql
db/pacific_06_trips.sql
db/pacific_07_import_perms.sql
db/pacific_08_import_perms.sql
db/pacific_09_accounting_foundation.sql
db/pacific_10_expenses.sql
db/pacific_11_fuel.sql
db/pacific_12_maintenance.sql
db/pacific_13_trip_enhancements.sql
db/pacific_14_work_requests.sql
db/pacific_15_gps_foundation.sql
db/pacific_16_alerts_outbox.sql
```

---

## 3 · `config/config.php` — production values

Copy `config/config.php` to server, edit these constants:

```php
define("DEBUG",            false);                 // MUST be false in prod
define("PROOT",            '/pacific/');           // match the subfolder / domain
define("DB_NAME",          'pacificlg_prod');
define("DB_USER",          'pacificlg_app');
define("DB_PASSWORD",      '<random 24-char>');
define("DB_HOST",          'localhost');

// Rotate these — never ship the dev defaults
define("GPS_INGEST_TOKEN", '<paste 32-hex from `openssl rand -hex 16`>');
define("CRON_TOKEN",       '<paste different 32-hex>');

// Beem Africa SMS — get from https://dashboard.beem.africa
define("BEEM_API_KEY",     '<beem key>');
define("BEEM_SECRET_KEY",  '<beem secret>');
define("BEEM_SENDER_ID",   'PACIFIC');            // approved sender ID

// Outbound email — Namecheap provides free SMTP with your domain
define("MAIL_FROM",        'alerts@pacificgroup.co.tz');
define("MAIL_FROM_NAME",   'Pacific Logistics');
```

---

## 4 · Cron jobs (cPanel → Cron Jobs)

Namecheap Stellar allows a **minimum 5-minute interval**. Set two entries:

| Interval | Command | Purpose |
|---|---|---|
| `*/5 * * * *` | `curl -s "https://your-domain.tld/pacific/Cron/tick?token=<CRON_TOKEN>" > /dev/null` | Alerts engine + outbox dispatch |
| `0 2 * * *` | `curl -s "https://your-domain.tld/pacific/Cron/nightly?token=<CRON_TOKEN>" > /dev/null` | Daily digests + housekeeping |

Cron output should go to `/dev/null`; every run also writes a row to `cron_runs`
which is your source of truth. Check `SELECT * FROM cron_runs ORDER BY c0d DESC LIMIT 20`
if you suspect a stall.

---

## 5 · Tracker configuration

### 5A · Mobile app (OsmAnd protocol — the free path)
Any driver phone running **OsmAnd Live Tracker** or **GPSLogger** points at:
```
POST https://your-domain.tld/pacific/GpsIngest/webhook?token=<GPS_INGEST_TOKEN>
```
Body: `{"deviceId":"<phone-id>","lat":..,"lon":..,"speed":..,"timestamp":..}`

### 5B · Hardware trackers via Traccar Cloud (paid, ~USD 5/tracker/mo)
1. Sign up at https://www.traccar.org/cloud/ (or https://demo.traccar.org for testing)
2. Add each Teltonika device (IMEI, model)
3. Under **Server Settings → Forwarding**, add URL:
   ```
   https://your-domain.tld/pacific/GpsIngest/webhook?token=<GPS_INGEST_TOKEN>
   ```
4. Format: **JSON** (Traccar sends `{device, position}` shape our webhook already speaks)

### 5C · Growth path: self-hosted Traccar (needs VPS, not shared)
Once fleet ≥ ~5 hardware trackers, break-even flips vs Traccar Cloud. At that point:
- Migrate to a Namecheap **VPS Pulsar** (~USD 12/mo, 2 GB RAM, root access)
- `apt install openjdk-17-jre-headless`, drop Traccar jar in `/opt/traccar`, systemd unit
- Point trackers at `tcp://vps-ip:5027` (Codec 8E)
- Configure Traccar → forward JSON to our webhook (same URL as above)
- No code changes on our side

---

## 6 · First-boot verification

Log in as Administrator, then:

- [ ] Dashboard renders without SQL errors
- [ ] `Trucks/index` shows seeded trucks
- [ ] `GpsDevices/index` shows empty state
- [ ] Register one device, note its IMEI
- [ ] Fire a test position:
  ```bash
  curl -X POST -H "Content-Type: application/json" \
    "https://your-domain.tld/pacific/GpsIngest/webhook?token=<GPS_INGEST_TOKEN>" \
    -d '{"deviceId":"<IMEI>","lat":-6.7924,"lon":39.2083,"speed":45,"timestamp":'$(date +%s)'}'
  ```
- [ ] Response: `{"ok":true,"ingested":1,"skipped":0,"errors":[]}`
- [ ] `Trucks/view/<id>` now shows a "Last known position" strip
- [ ] Cron tick fires:
  ```bash
  curl "https://your-domain.tld/pacific/Cron/tick?token=<CRON_TOKEN>"
  ```
- [ ] `SELECT * FROM cron_runs` shows a fresh row

---

## 7 · Known shared-hosting limits & workarounds

| Limit | Workaround |
|---|---|
| Cron min interval 5 min | Alerts engine uses 5-min tick + watermark; over-speed alerts fire up to 5 min late |
| PHP `max_execution_time` 30–60 s | Cron worker batches ≤ 200 positions per tick and self-limits by wallclock |
| No persistent TCP listener | Hardware trackers reach us via Traccar Cloud → HTTP forward; no direct TCP |
| Concurrent MySQL conn cap ~25 | Never a problem at Pacific scale (~20 trucks × 1 conn/req) |
| Outbound port 25 blocked | Use SMTP on 465/587 via `PHPMailer` (Namecheap provides mailboxes with SMTP) |
| No websockets on shared | Live map polls `/GpsDevices/latestJson` every 30 s — good enough for MVP |

---

## 8 · Backup & rotation

- cPanel → Backup → **JetBackup** runs nightly (retention: 4 weekly + 4 monthly by default)
- Weekly test-restore of `pacificlg_prod` to a staging DB (once a month at minimum)
- Rotate `GPS_INGEST_TOKEN` and `CRON_TOKEN` **every 90 days** and after every staff departure with `config/config.php` access

---
_Doc owner: Rookasystems. Update when adding new SQL slices or config keys._
