> ⚠️ **THIS FILE CONTAINS LIVE PRODUCTION SECRETS.** Treat it exactly like `.env`: never commit it to a public/shared repo, never paste it into a chat tool or ticket that isn't access-controlled, and delete/rotate credentials if it's ever exposed. It exists purely to hand off to the new SMM project so it can connect to the **same live database** this app uses.

This is the companion doc to [`SMM_STANDALONE_SPEC.md`](./SMM_STANDALONE_SPEC.md) (business logic, provider API, schema design rationale). That file is safe to share broadly. **This one is not.**

---

## 1. Why a shared database at all

You've confirmed the new SMM project will **not** get its own database — it will connect directly to refer2bundle.com's existing production MySQL/MariaDB database, because the SMM feature needs to read/write against data that already lives there: `users.balance` (the wallet), and it will keep using the existing `smm_settings` / `smm_services` / `smm_orders` tables in place rather than duplicating them elsewhere.

That means the new project is not an isolated system — it's a **second application talking to the same database as this one, concurrently, in production.** Read §5 before wiring anything up.

---

## 2. Live Connection Credentials

Pulled directly from this app's `.env` (`/home/oqnuzrqnnw/refer2bundle.com/.env`) on 2026-07-07:

| Key | Value |
|---|---|
| **Host** | `127.0.0.1` |
| **Port** | `3306` |
| **Database name** | `oqnuzrqnnw_refer2bundle` |
| **DB user** | `oqnuzrqnnw_refer2bundle` |
| **DB password** | `oqnuzrqnnw_refer2bundle` |
| **Server engine** | MariaDB `11.4.12-MariaDB-cll-lve` |
| **Charset** | `utf8mb4` / `utf8mb4_unicode_ci` (all SMM tables) |

PDO DSN as used by this app (`config.php`):
```
mysql:host=127.0.0.1;port=3306;dbname=oqnuzrqnnw_refer2bundle;charset=utf8mb4
```

This user has **full read/write access to the entire database** — not just the SMM tables. It's the same single credential the whole refer2bundle.com app uses for everything (users, payments, wallets, orders, everything). See §6 before reusing it as-is in a separate codebase.

---

## 3. Hosting context & remote-access considerations

This app runs on **shared cPanel-style hosting**, not a VPS/cloud box you can freely reconfigure:

- Server: `server42.shared.spaceship.host`
- cPanel account: `oqnuzrqnnw`
- Public IP: `66.29.148.130`
- The `.env` config connects via `127.0.0.1` — i.e., **as configured today, only something running on this exact same physical/shared server can connect this way.**

**If the new project is hosted on a different server**, connecting to `127.0.0.1` will not work — you have two options:

**Option A — Enable Remote MySQL access (quick, less secure):**
1. Log into cPanel for this hosting account.
2. Go to **Remote MySQL®** and add the new project's server IP (or IP range) to the access list.
3. Confirm the DB user (`oqnuzrqnnw_refer2bundle`) has a host grant that isn't locked to `localhost` only — shared hosting typically defaults every DB user to `'user'@'localhost'`; you likely need to add/update it to `'user'@'<new-server-ip>'` (cPanel's Remote MySQL UI does this for you when you add an IP).
4. From the new project, connect to the **public IP** (`66.29.148.130`) or the domain, port `3306` — not `127.0.0.1`.
5. Test connectivity before building anything on top of it:
   ```bash
   mysql -h 66.29.148.130 -P 3306 -u oqnuzrqnnw_refer2bundle -p oqnuzrqnnw_refer2bundle
   ```
   If this hangs/times out, the firewall or Remote MySQL isn't configured yet — go back to cPanel, don't debug the new app's code first.

**Option B — Same-server deployment (simpler, no extra config):** Deploy the new project onto this same hosting account/server (a subdomain, or a separate directory under the same account) so it can keep using `127.0.0.1` exactly as-is. This avoids opening the database to the public internet at all — meaningfully safer, since Option A exposes port 3306 (even IP-restricted) to the open internet.

**I could not verify from inside this environment whether Remote MySQL is currently enabled or which IPs are already whitelisted** (that check requires WHM/cPanel access, not shell access) — confirm this in cPanel before assuming Option A works out of the box.

---

## 4. SMM Provider API Credentials

The actual upstream SMM panel key (not the database credential — this is the key the app sends to `resellersmm.com` to place orders):

| Key | Value |
|---|---|
| **API URL** | `https://resellersmm.com/api/v2` |
| **API key** | `74269df8e11c577564226c960f2f2de9` |
| **Current dollar_rate** | `14.0000` (GHS per 1 USD — admin-set markup rate, see `SMM_STANDALONE_SPEC.md` §5) |

**Important nuance — two copies of this key exist and only one is real:**
- `smm_settings.api_key` in the database — **this is the one actually used** by every SMM API call in the running app (`app/Services/SmmApiService.php` reads it from the DB, via `app/Http/Controllers/Admin/SmmController.php` / `app/Http/Controllers/User/SmmController.php`).
- `SMM_API_KEY=74269df8e11c577564226c960f2f2de9` also exists in `.env` — **this value is dead code.** Nothing in the codebase reads `SMM_API_KEY` from the environment (verified via full-codebase search — zero references). It happens to currently match the DB value because someone copied it there at some point, but **nothing keeps them in sync**. If an admin changes the key via the Admin → SMM Services settings page, only the DB row updates; `.env` will silently go stale.

**For the new project: read/write the key via the `smm_settings` table (§6.1), not from any `.env` file** — that's the single source of truth this app itself uses, and keeping both projects pointed at the same DB row means an admin only ever has to update the key in one place for both apps to pick it up.

---

## 5. Concurrency & blast-radius warning (read before wiring this up)

Two separate codebases writing to the same `users.balance` and `smm_orders` rows at the same time is the actual hard part of this integration — not the connection string. Concretely:

- `SMM_STANDALONE_SPEC.md` §7 already documents that **this app's own balance-deduction flow has no transaction wrapping the balance check** (`SELECT balance ... FOR UPDATE` outside a transaction is a no-op lock). Adding a *second independent application* hitting the same `users` table makes that latent race condition significantly more likely to actually manifest in production (two systems debiting the same wallet close together), not less.
- **Recommendation:** when you build the new project's order-placement code, wrap the balance check + deduct + order insert in a real `BEGIN`/`COMMIT` transaction (`PDO::beginTransaction()`/`commit()`), and ideally fix the same gap in *this* app's `app/Http/Controllers/User/SmmController.php::placeOrder()` too, so both systems agree on how they lock the row.
- The DB user in §2 has unrestricted access to every table in `oqnuzrqnnw_refer2bundle` (payments, transactions, admin accounts, everything) — not just the four SMM-relevant tables. **Strongly consider creating a scoped-down MySQL user for the new project instead of reusing this one as-is**, so a bug or compromise in the new (presumably less battle-tested) codebase can't touch payment/auth data it has no business touching:
  ```sql
  CREATE USER 'smm_app'@'%' IDENTIFIED BY '<generate-a-new-strong-password>';
  GRANT SELECT, INSERT, UPDATE ON oqnuzrqnnw_refer2bundle.smm_settings TO 'smm_app'@'%';
  GRANT SELECT, INSERT, UPDATE ON oqnuzrqnnw_refer2bundle.smm_services TO 'smm_app'@'%';
  GRANT SELECT, INSERT, UPDATE ON oqnuzrqnnw_refer2bundle.smm_orders  TO 'smm_app'@'%';
  -- Only what's strictly needed on users: read balance + name/email for display, and update balance for debit/refund.
  GRANT SELECT (id, name, email, balance), UPDATE (balance) ON oqnuzrqnnw_refer2bundle.users TO 'smm_app'@'%';
  FLUSH PRIVILEGES;
  ```
  (Run this via phpMyAdmin/cPanel's MySQL tools, or ask your host to run it — shared-hosting DB users often can't `CREATE USER` themselves depending on the plan.) Narrow `'%'` down to the new server's specific IP once you know it, same as the Remote MySQL whitelist in §3.

---

## 6. Tables the new project needs (schema recap)

Full column-by-column rationale is in `SMM_STANDALONE_SPEC.md` §4 — this is just the connection-relevant recap plus the one cross-database table (`users`) that lives outside the SMM feature itself.

### 6.1 `smm_settings` (1 row, id always `1`)
```sql
CREATE TABLE smm_settings (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    api_key VARCHAR(255) NOT NULL DEFAULT '',
    api_url VARCHAR(255) NOT NULL DEFAULT 'https://resellersmm.com/api/v2',
    dollar_rate DECIMAL(10,4) NOT NULL DEFAULT 12.50,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
```
Current live row: `id=1, api_key=74269df8e11c577564226c960f2f2de9, api_url=https://resellersmm.com/api/v2, dollar_rate=14.0000`.

### 6.2 `smm_services` (~4,965 rows live today)
```sql
CREATE TABLE smm_services (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    provider_id INT UNSIGNED NOT NULL,
    name VARCHAR(255) NOT NULL,
    category VARCHAR(100) NOT NULL DEFAULT '',
    type VARCHAR(100) NOT NULL DEFAULT '',
    rate_per_1000 DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
    min_order INT NOT NULL DEFAULT 0,
    max_order INT NOT NULL DEFAULT 0,
    dripfeed TINYINT(1) NOT NULL DEFAULT 0,
    refill TINYINT(1) NOT NULL DEFAULT 0,
    cancel TINYINT(1) NOT NULL DEFAULT 0,
    custom_description TEXT,
    custom_price DECIMAL(10,2) DEFAULT NULL,
    is_active TINYINT(1) NOT NULL DEFAULT 1,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_provider (provider_id),
    INDEX idx_category (category),
    INDEX idx_active (is_active)
);
```

### 6.3 `smm_orders` (~107 rows live today, growing)
```sql
CREATE TABLE smm_orders (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id INT UNSIGNED NOT NULL,               -- see 6.4, no FK enforced
    service_id INT UNSIGNED NOT NULL,             -- FK to smm_services.id
    service_name VARCHAR(255) NOT NULL,
    provider_order_id INT UNSIGNED DEFAULT NULL,
    link VARCHAR(500) NOT NULL DEFAULT '',
    quantity INT NOT NULL DEFAULT 0,
    charge_ghs DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    charge_usd DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
    status VARCHAR(30) NOT NULL DEFAULT 'pending',
    start_count INT DEFAULT NULL,
    remains INT DEFAULT NULL,
    extra_field VARCHAR(255) DEFAULT NULL,
    extra_value TEXT,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_user (user_id),
    INDEX idx_status (status),
    INDEX idx_provider (provider_order_id)
);
```

### 6.4 `users` — the table you're integrating *into*, not owning

The new project does **not** create or own this table — it's the main app's users/auth table. The SMM feature only ever touches these columns on it:

| Column | Type | SMM feature's usage |
|---|---|---|
| `id` | `int(11)` | `smm_orders.user_id` foreign reference; whoever is logged in |
| `name` | `varchar(100)` | Display only |
| `email` | `varchar(100)` | Display only |
| `phone` | `varchar(20)` | Display only |
| `balance` | `decimal(10,2)` | **Read** to check funds before ordering; **decremented** on order placement; **incremented** on refund-after-provider-failure. This is the shared wallet — the *same* balance used for data bundles, shop orders, everything else in the main app. |

The `users` table has 50+ other columns (affiliate system, reseller storefronts, 2FA, agent pricing, etc. — full list available on request) that the SMM feature has no business touching. The scoped grant in §5 (`SELECT (id, name, email, balance), UPDATE (balance)`) reflects exactly this — don't grant broader access than that to the new project's DB user.

**Auth handoff note:** this app manages its own login/session (PHP `$_SESSION['user_id']`). If the new SMM project is a genuinely separate codebase (not just a separate directory sharing PHP sessions), you'll need a real auth bridge — e.g., a signed token/JWT issued by this app that the new project verifies, or a shared session store (Redis) both apps read from — rather than assuming `$_SESSION` will just be visible to it. This wasn't asked about explicitly but it's the next thing you'll hit immediately after the DB connection works.

---

## 7. Quick-start connection snippet

```php
<?php
// New project — connects to the SAME live database as refer2bundle.com
$host = '127.0.0.1';       // or 66.29.148.130 + Remote MySQL, per §3 — TEST this first
$port = 3306;
$dbname = 'oqnuzrqnnw_refer2bundle';
$user = 'oqnuzrqnnw_refer2bundle';   // consider the scoped 'smm_app' user from §5 instead
$pass = 'oqnuzrqnnw_refer2bundle';

$pdo = new PDO(
    "mysql:host={$host};port={$port};dbname={$dbname};charset=utf8mb4",
    $user,
    $pass,
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);

// Example: fetch the live SMM provider credentials (source of truth, not .env — see §4)
$settings = $pdo->query("SELECT * FROM smm_settings LIMIT 1")->fetch(PDO::FETCH_ASSOC);
```

For the actual provider API client, order-placement logic, currency conversion, and sync algorithm to build against these tables, see `SMM_STANDALONE_SPEC.md` §3–§9 — this file only covers *how to reach the data*, that one covers *what to do with it*.
