# Nadiplayer · cPanel Deployment Guide — v1.2.0

> **Short answer: NO, you do NOT need Node.js or Python on cPanel.**
> The PHP backend in this repo is feature-complete (Xtream / M3U /
> Stalker / FCM Push / Live Stats) and runs on every shared cPanel host
> that has PHP 8 with the standard `curl`, `openssl`, `mongodb` and
> `json` extensions enabled.

This guide walks you through deploying everything that landed in
v1.2.0:

* The new **Broadcast Notification** admin page
* **FCM Push** with rich notifications + per-user targeting
* **Live Stats** counters (live watchers, total installs, DAU/WAU)
* **Auto profile loading** + new **Select Profile** screen
* **Stalker / MAC** support in shared profiles
* The slimmer **mobile bottom nav** + landscape hide

---

## 0. Prerequisites — check your cPanel host

Open **cPanel → Select PHP Version** and confirm:

| Requirement | Where to check |
|---|---|
| PHP **8.0 or newer** | "Current PHP version" dropdown |
| `curl` extension | "Extensions" tab — must be ✅ |
| `openssl` extension | same |
| `json` extension | same |
| `mongodb` extension | same — if missing, see **Appendix B** |

If `mongodb` is missing on your shared host, see the bottom of this
guide for two work-arounds.

---

## 1. Generate the build artefacts (one-time, on your dev machine)

Anywhere with Node.js / yarn:

```bash
cd /app/frontend
yarn install
yarn build                # produces dist/ (HTML + JS + CSS bundle)
```

Result: `frontend/dist/` contains `index.html` + `assets/*.js,css` —
this is what you upload to the public document root on cPanel.

---

## 2. What goes where on cPanel

Assuming your domain serves the app from
`public_html/4kmovies.vip/nadiplayer/`, the layout looks like this:

```
public_html/4kmovies.vip/nadiplayer/
├── index.html                 ← from frontend/dist/
├── assets/                    ← from frontend/dist/assets/
├── images/                    ← from frontend/public/images/
├── locales/                   ← from frontend/public/locales/
├── manifest.webmanifest       ← from frontend/dist/  (optional)
└── api/
    ├── .htaccess              ← rewrites to index.php
    ├── index.php              ← FROM cpanel_build_php/nadiplayer/api/
    ├── config.php
    ├── lib/                   ← lib/util.php, db.php, auth.php
    ├── routes/                ← all routes/*.php
    │   ├── auth.php
    │   ├── admin.php
    │   ├── public.php
    │   ├── device.php
    │   ├── iptv_proxy.php
    │   ├── stalker.php
    │   ├── notifications.php  ← NEW in v1.2.0
    │   └── stats.php          ← NEW in v1.2.0
    └── secrets/
        └── firebase-service-account.json  ← NEW in v1.2.0 (chmod 0600)
```

### Step-by-step

1. **Open cPanel → File Manager** → navigate to the `nadiplayer/`
   folder.
2. **Backup first.** Right-click `api` → Compress → download the .zip.
3. **Upload the new front-end bundle.** Delete the old `assets/` folder
   then upload the contents of `frontend/dist/` (the `index.html` and
   the new `assets/` folder).
4. **Upload the new API files** (this is the part that gives you the
   Broadcast button + Live Stats):
   - `api/index.php`          (overwrite — has the new route table)
   - `api/routes/notifications.php`   (NEW — upload)
   - `api/routes/stats.php`           (NEW — upload)
   - `api/routes/admin.php`           (overwrite — bumped version
     defaults to 1.2.0)
   - All other `api/routes/*.php` files are unchanged from v1.1.0,
     but uploading them anyway is harmless.
5. **Place the Firebase service-account key.** Inside `api/`, create a
   folder `secrets/` and upload your
   `nadiplayer-firebase-adminsdk-fbsvc-XXXXXX.json`, **renamed to**:
   ```
   api/secrets/firebase-service-account.json
   ```
   Then right-click → **Change Permissions** → set to **0600**
   (owner read/write only) so other accounts on the shared host
   can't read it.
6. **Verify the `secrets/` folder is not browsable.** The supplied
   `.htaccess` in the upgrade-kit denies `Indexes` for `api/`, but
   adding an explicit guard is wise — see *Appendix A* below.

---

## 3. Smoke test (60 seconds)

Replace `https://YOUR_DOMAIN` with your real URL. From any terminal:

```bash
# 3.1  Public endpoints respond
curl -s https://YOUR_DOMAIN/api/public/app-info | jq .update.latest_version
# → "1.2.0"

# 3.2  Login as admin
TOKEN=$(curl -s -X POST https://YOUR_DOMAIN/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"YOUR_ADMIN_PW"}' \
  | jq -r .access_token)

# 3.3  Empty broadcast list (200 OK with empty array on first deploy)
curl -s https://YOUR_DOMAIN/api/admin/broadcasts \
     -H "Authorization: Bearer $TOKEN" | jq .

# 3.4  FCM access-token exchange works (will queue but report
#      "No registered devices" until the first phone registers)
curl -s -X POST https://YOUR_DOMAIN/api/admin/broadcast-notification \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Hello","body":"world","route":"/live-tv"}' | jq .
# Expected: {"queued": false, "error": "No registered devices"}
# (which proves Firebase SDK is happy — the JSON is valid, the
# private key signs correctly, OAuth 2 token exchange succeeds)
```

If step 3.4 returns a 503 with `"Firebase service account not found"`
or `"FCM token exchange failed"`, recheck step 5 above (file path,
permissions, JSON not corrupted by the upload).

---

## 4. Trigger the new admin UI in the browser

1. Hard-refresh your admin URL (Ctrl+Shift+R) to defeat the cache.
2. Log in as admin.
3. You should now see, **at the top of the Admin page**:
   - A new **Engagement** card with three numbers (Live now / Installs /
     Active 24h) auto-refreshing every 30 seconds.
   - The numbers stay at zero until your first user installs the new
     APK and starts watching — that's normal.
4. In the header next to "Refresh", you'll see a new **Broadcast**
   button (megaphone icon). Click it → you're on `/admin/broadcast`
   with these fields:
   - Title
   - Message
   - Tap action (route picker · Live TV / Movies / Series / Home / none)
   - **NEW** Image URL (rich notification thumbnail)
   - **NEW** Action button label (e.g. "Watch Now")
   - **NEW** Recipient (All users vs single user dropdown)

> If you don't see the Broadcast button after a hard-refresh, your
> browser is still serving the old `index.html` from a service-worker
> cache. Open DevTools → Application → Service Workers → **Unregister**,
> then refresh.

---

## 5. Build & ship the Android APK

```bash
cd /app/frontend
yarn build
npx cap sync android
cd android
./gradlew assembleRelease
# APK: android/app/build/outputs/apk/release/app-release.apk
# versionName 1.2.0 / versionCode 22
```

After install, on first launch:
- Android 13+ asks "Allow notifications?" → tap **Allow**.
- After the user signs in and starts a stream, the heartbeat sent by
  `useHeartbeat` will populate the **Live now** counter on the admin
  page within a minute.

Send a test broadcast from the admin (with an image URL like the
official match poster) → should arrive on the phone with the
thumbnail visible and "Watch Now" as the tap-target.

---

## 6. Troubleshooting matrix

| Symptom | Most likely cause | Fix |
|---|---|---|
| Admin sees "No route for POST /api/admin/broadcast-notification" 404 | Forgot to overwrite `api/index.php` | Re-upload `api/index.php` and verify file size matches the cpanel_build_php source |
| Broadcast returns 503 "Firebase service account not found at /…/secrets/firebase-service-account.json" | File missing or wrong path | Place file at exactly `api/secrets/firebase-service-account.json`, chmod 0600 |
| 502 "FCM token exchange failed: HTTP 403" | Service-account key was revoked / project mismatch | Re-generate from Firebase Console → Service Accounts → "Generate new private key" |
| Phone gets the notification but tap doesn't open Live TV | Old APK without the v1.2.0 deep-link handler | Rebuild APK with `npx cap sync android` then reinstall |
| `mongodb` extension missing | Shared host doesn't ship it | See Appendix B (use cPanel's PHP Selector, or fall back to the Python backend on a sub-domain) |
| 403 on `/api/secrets/firebase-service-account.json` if accessed in browser | Good — that's the `Deny from all` working | (no fix — leave it) |
| `/api/stats/heartbeat` returns 401 for guest user | Guest mode has no token | Expected — only signed-in users contribute to live stats |
| "Broadcast" button not visible in admin | Browser cached old bundle | Unregister service worker + hard refresh |

---

## 7. Optional but recommended

* **Cloudflare in front of /api/** — cache `Cache-Control: public, max-age=60` on `/api/public/app-info` and `/api/shared-profiles` to slash backend load.
* **Daily MongoDB backup** — cPanel → Backup Wizard → schedule weekly.
* **2-factor on the admin user** — wire later via Google Authenticator (TOTP), straightforward on top of the existing JWT login.

---

## Appendix A — protect `secrets/` with `.htaccess`

Create `api/secrets/.htaccess`:

```apache
# Don't ever serve files in this folder over HTTP.
Require all denied
Options -Indexes
```

This is belt-and-suspenders on top of the `chmod 0600`.

---

## Appendix B — what if my host has no `mongodb` PHP extension?

You have three options, in order of effort:

1. **Use cPanel's PHP Selector → Extensions → tick "mongodb"**
   (most managed cPanel hosts let you self-enable this; cost: free).
2. **Ask your host to enable it** — almost every host (HostGator,
   Bluehost, A2, Namecheap shared, …) will turn it on for paying
   customers within a day.
3. **Run only the Python backend on a sub-domain.** This is a fall-
   back: keep your front-end at `https://app.YOUR_DOMAIN/`, point
   `REACT_APP_BACKEND_URL` at `https://api.YOUR_DOMAIN/` where you
   spin up a small Python container. cPanel hosts that support
   "Application Manager" / "Setup Python App" (most cPanel >= 90)
   make this two clicks. The Python backend is at
   `/app/backend/` in this repo; deploy with:
   ```bash
   pip install -r requirements.txt
   uvicorn server:app --host 0.0.0.0 --port 8001
   ```
   Then add a `.env` with `MONGO_URL`, `DB_NAME`, `JWT_SECRET`,
   `FERNET_KEY`, `ADMIN_PASSWORD` like the local dev one.

---

## Version log (truncated)

| Version | What landed |
|---|---|
| **1.2.0** | Push: rich notifications, per-user targeting · Live Stats card · Heartbeat · Cleaner deployment guide |
| 1.1.0 | FCM push notifications (Python backend) + Capacitor plugin + Admin Broadcast page |
| 1.0.9 | PiP, Background playback, MediaSession |
| 1.0.8 | Select Profile screen + auto-load on login |
| 1.0.7 | Auto-mirror admin shared profiles into local store |
| 1.0.6 | Stalker / MAC support in upgrade-kit |
| 1.0.5 | Mobile slim bottom nav + landscape hide |
| 1.0.4 | Inline Preview Player toggle propagation |
