# Client master DB (`skcsolut_clientmaster`) — separate connection

Tenant data and client master use **different** MySQL credentials on dedicated APIs (e.g. HJ).

| Purpose | Env vars | Example (HJ) |
|---------|----------|----------------|
| Tenant app DB | `DB_HOST`, `DB_USER`, `DB_PASSWORD`, `DB_NAME_DEV` | `127.0.0.1`, `hjenterprisesco_user`, …, `hjenterprisesco_skcs` |
| Client master | `MASTER_DB_*` + `CLIENT_MASTER_DB` | `66.116.199.166`, `skcs_master_read`, …, `skcsolut_clientmaster` |

If `MASTER_DB_HOST` / `MASTER_DB_USER` / `MASTER_DB_PASSWORD` are **omitted** from the target `.env`, the app falls back to `DB_*` for master at runtime.

**Backend deploy** writes `MASTER_DB_*` on **every** API deploy when the orchestrator has `MASTER_DB_PASSWORD` or `DB_PASSWORD` set:

| Deploy type | `DB_HOST` (tenant) | `MASTER_DB_HOST` (default if unset on orchestrator) |
|-------------|-------------------|-----------------------------------------------------|
| Shared (devapi, etc.) | `66.116.199.166` | same as tenant host |
| Dedicated (HJ, etc.) | `127.0.0.1` | `66.116.199.166` (remote client master) |

Code: [`config/masterPool.js`](../config/masterPool.js).

**Troubleshooting `Client lookup failed` + tenant user `@localhost`:** the API is querying client master with tenant `DB_*` (master pool fell back) and/or `DB_NAME_DEV` was not loaded. Ensure pm2 **cwd** is the backend folder (deploy restarts from `BACKEND_PATH`), and use [`loadEnv.js`](../loadEnv.js) so `.env` is read from the app directory, not `process.cwd()`. After restart, pm2 logs should show `DB_NAME_DEV=hjenterprisesco_skcs` and `master=66.116.199.166:skcs_master_read@...` (or your master user).

---

## 1. MySQL user (on skcsolut / shared server)

Create a **read-only** user for dedicated APIs (recommended):

```sql
CREATE USER IF NOT EXISTS 'skcs_master_read'@'%' IDENTIFIED BY 'strong_password_here';

GRANT SELECT ON skcsolut_clientmaster.* TO 'skcs_master_read'@'%';

FLUSH PRIVILEGES;
```

Restrict host instead of `%` when you know the dedicated server IP:

```sql
CREATE USER IF NOT EXISTS 'skcs_master_read'@'HJ_SERVER_PUBLIC_IP' IDENTIFIED BY '...';
GRANT SELECT ON skcsolut_clientmaster.* TO 'skcs_master_read'@'HJ_SERVER_PUBLIC_IP';
```

MySQL 8+ may require:

```sql
CREATE USER IF NOT EXISTS 'skcs_master_read'@'%' IDENTIFIED BY '...';
GRANT SELECT ON skcsolut_clientmaster.* TO 'skcs_master_read'@'%';
```

Use a user with more privileges only on the **deploy orchestrator** (devapi), not on every dedicated `.env`, unless you accept that risk.

---

## 2. cPanel (skcsolut account)

1. **MySQL® Databases** — create user `skcs_master_read` and add **SELECT** on `skcsolut_clientmaster` (or use phpMyAdmin → User accounts → privileges).
2. **Remote MySQL®** — add the **outbound IP** of the dedicated API server (HJ host), or the IP from which connections originate, so `MASTER_DB_HOST=66.116.199.166` works from HJ pm2.

Test from HJ server SSH:

```bash
mysql -h 66.116.199.166 -u skcs_master_read -p skcsolut_clientmaster -e "SELECT COUNT(*) FROM client;"
```

---

## 3. Deploy orchestrator (devapi) `.env`

Set once on the server that runs **backend deploy** (admin deploy UI). These values are copied into **dedicated** client API `.env` files on deploy:

```env
MASTER_DB_HOST=66.116.199.166
MASTER_DB_USER=skcs_master_read
MASTER_DB_PASSWORD=the_read_only_password
```

If unset, deploy falls back to `DB_USER` / `DB_PASSWORD` on the orchestrator (often `skcsolut_root`) when writing dedicated targets.

---

## 4. Dedicated API `.env` (after backend deploy)

Example for HJ:

```env
DB_HOST=127.0.0.1
DB_USER=hjenterprisesco_user
DB_PASSWORD=...
DB_NAME_DEV=hjenterprisesco_skcs

MASTER_DB_HOST=66.116.199.166
MASTER_DB_USER=skcs_master_read
MASTER_DB_PASSWORD=...
CLIENT_MASTER_DB=skcsolut_clientmaster

PUBLIC_HTML_ROOT=/home/hjenterprisesco/public_html
TENANT_MODE=dedicated
CLIENT_URL=hjenterprises.co.in
CORS_API_URL=https://hjapi.hjenterprises.co.in/api/v1
```

Restart pm2 after deploy.

---

## 5. Verify

**pm2 logs** on API startup:

- `Master Pool connecting to 66.116.199.166:skcs_master_read@skcsolut_clientmaster (MASTER_DB_*)`
- `CORS origins loaded: ... (scoped API ..., M client row(s) from DB)` with `M > 0` if master refresh works

**Manual** (on API server):

```bash
node -e "require('dotenv').config(); const p=require('./config/masterPool'); p.query('SELECT 1').then(()=>console.log('ok')).catch(e=>console.error(e));"
```

Run from the Backend directory with production `.env`.

---

## 6. Security

- Prefer **read-only** `MASTER_DB_USER` on dedicated hosts.
- Do not commit `MASTER_DB_PASSWORD` to git.
- Rotate passwords if they were exposed in chat or logs.
