# Release Bundle — v1.3.1

This folder contains **everything you need to upload to cPanel**, already
built and pre-arranged in the exact tree you should put under
`public_html/nadi.kr/`.

## What's new in v1.3.1

| Feature | Location |
|---------|----------|
| **Privacy Policy page** (for Google Play Console) | `PrivacyPolicy/index.html` — served at `https://nadi.kr/PrivacyPolicy/` |
| **Device-identity aware pairing**: `/api/device/register` now accepts `{ mac_address, hardware_id, model }` from the Android client, prevents duplicate device rows (keyed by `hardware_id`), and never returns the `00:00:00:00:00:00` placeholder | `api/routes/device.php` |
| **Automatic DB migration** adds `hardware_id` + `model` columns to `devices` on first request | `api/routes/device.php` |
| **Hardened `/pair/` portal**: double-submit guard, auto-prefix `http://` on bare domain input, better server-error surfacing | `pair/index.html` |
| **In-app Unpair button** — users can unpair their device from the Account screen (Android app) | Android app — ship with the APK rebuilt from the updated source |
| **Android package rename** `com.nadiplayer.app` → **`com.nadi.player`** | Android app |
| **Hard-coded QR pair URL** `https://nadi.kr/pair/` instead of `https://localhost/pair` | Android app |

## Folder layout

```
release-bundle/
└── nadiplayer/                    ← drop the contents of this folder
    │                                under your domain root
    │
    ├── .htaccess                  ← SPA fallback (real folders like
    │                                  /PrivacyPolicy/, /pair/,
    │                                  /subscription/ bypass the SPA)
    ├── index.html                 ← SPA entry
    ├── assets/                    ← compiled JS/CSS chunks
    ├── images/, audio/, favicon, etc.  (static assets)
    │
    ├── PrivacyPolicy/             ← NEW v1.3.1 — Google Play-ready policy
    │   └── index.html                 (https://nadi.kr/PrivacyPolicy/)
    │
    ├── subscription/              ← standalone payment page
    │   └── index.html                 (https://nadi.kr/subscription/)
    │
    ├── pair/                      ← standalone pairing page (hardened in 1.3.1)
    │   └── index.html                 (https://nadi.kr/pair/)
    │
    ├── admin_panel/               ← PHP admin (unchanged)
    │
    └── api/
        ├── .htaccess
        ├── index.php              ← front controller
        ├── config.php             ← MySQL creds + Stripe/PayPal keys
        ├── lib/{auth,db,util}.php
        ├── routes/
        │   ├── auth.php
        │   ├── admin.php
        │   ├── public.php
        │   ├── device.php         ← ⚡ UPDATED — dedupe by hardware_id,
        │   │                           accepts client MAC + ANDROID_ID
        │   ├── iptv_proxy.php
        │   ├── stalker.php
        │   ├── notifications.php
        │   ├── stats.php
        │   └── payments.php
        └── secrets/
            ├── .htaccess
            └── README.txt
```

---

## 1. Upload (3 minutes)

1. Open **cPanel → File Manager** → go to `public_html/nadi.kr/`.
2. Upload `nadiplayer-1.3.1.zip` and extract it there, overwriting existing files.
3. Show hidden files (dotfiles) in cPanel File Manager so `.htaccess` uploads correctly.

## 2. Verify Privacy Policy page

Open `https://nadi.kr/PrivacyPolicy/` — you should see the
styled privacy policy. Paste this URL into **Google Play Console →
App content → Privacy Policy**.

## 3. Verify the new pairing contract

```bash
# Should respond with a new row that echoes back the MAC you sent:
curl -s -X POST https://nadi.kr/api/device/register \
  -H "Content-Type: application/json" \
  -d '{"mac_address":"AA:BB:CC:11:22:33","hardware_id":"abcdef1234567890","model":"Samsung SM-G991U"}'

# Second call with the SAME hardware_id MUST return the same device_id
# and `"reused": true` — this is the duplicate-prevention guarantee.
```

The first-hit registration auto-migrates the `devices` table to add
`hardware_id` + `model` columns and an index — no manual SQL required.

## 4. Payment providers (unchanged from 1.3.0)

Edit `api/config.php` and fill in Stripe + PayPal keys as before. See
the v1.3.0 notes if you're setting this up for the first time.

---

## How the pairing wires together (v1.3.1)

1. Android app (`com.nadi.player`) reads the most stable identity it can
   from the OS via the `DeviceIdentity` Capacitor plugin — real WiFi/ethernet
   MAC when the kernel exposes it, otherwise `Settings.Secure.ANDROID_ID`
   formatted as a locally-administered MAC so legacy UI keeps rendering.
2. App calls `POST /api/device/register` with
   `{ mac_address, hardware_id, model }`. Server:
   - If `hardware_id` matches an existing row → returns the **same**
     `device_id` + current `pin` with `"reused": true`. No duplicate.
   - Else inserts a new row, storing the best MAC available (real > MAC
     derived from `hardware_id` > pseudo-MAC).
3. App shows the MAC + Device ID + 6-digit PIN + QR code pointing to
   `https://nadi.kr/pair/?pin=XXXXXX`.
4. User opens that URL on phone/PC, enters PIN + Xtream credentials.
5. Page calls `POST /api/device/pair`.
6. App's `GET /api/device/status/{device_id}` polling sees
   `paired=true` and fetches credentials via
   `GET /api/device/config/{device_id}`.

Users can **unpair** any time from the Account screen — this calls
`DELETE /api/device/unpair/{device_id}`, which regenerates the PIN
so the device can be paired to a fresh IPTV profile.
