# Kaabe SaaS POS 1.0.0 — InMotion STAGING deployment

This guide installs a **separate staging copy** of Kaabe on InMotion (cPanel). Staging uses its own domain, its own
central database, its own test businesses and its own test business databases. It never uses or connects to
`ssgplatforms_deeq` or any other production database, production DNS record or production credential.

Use `INSTALLATION.md` for the full reference of every setting; this guide is the exact order to follow for staging.
Tick each item in `STAGING-ACCEPTANCE-CHECKLIST.md` afterwards.

---

## 0. Decide where staging lives (read first)

| Option | What it is | Safety | Choose when |
|---|---|---|---|
| **A. Separate cPanel account (recommended)** | A second cPanel account (VPS/Dedicated/Reseller WHM, or a second hosting plan) used only for staging | The cPanel API token and database users of staging **cannot reach** production databases at all | Always, if InMotion can provide it |
| B. Same cPanel account as production | Staging in its own folder (`~/kaabe-staging`) with its own domain | The cPanel API token can manage **every** database of the account, including `ssgplatforms_deeq`. Kaabe's protected-database guard refuses that name, but the token itself is account-wide | Only if A is impossible |

**Domain:** use a domain or subdomain that production does not use, e.g. a new domain `kaabe-staging.com`, or
`staging.<your-domain>`. Adding new staging records does not change any existing production record, but if production
DNS must not be touched at all, use a **separate staging domain** (option A + new domain is the cleanest).

In the rest of this guide:

| Placeholder | Example | Meaning |
|---|---|---|
| `<user>` | `kaabestg` | the cPanel user of the staging account |
| `<base>` | `staging.example.com` | staging base domain |
| `admin.<base>` | `admin.staging.example.com` | Super Admin |
| `<slug>.<base>` | `alpha.staging.example.com` | one test business |
| `<root>` | `/home/<user>/kaabe` (option B: `/home/<user>/kaabe-staging`) | installation folder |

---

## 1. PHP 8.3 and extensions

1. cPanel → **MultiPHP Manager** → select `admin.<base>` and every business subdomain (and the wildcard, if used) →
   **PHP 8.3 (ea-php83)** → Apply.
2. cPanel → **Select PHP Version** / **MultiPHP INI Editor → Extensions** (the name depends on the server) — these must be enabled:
   `pdo_mysql mysqli openssl mbstring tokenizer xml dom simplexml ctype json bcmath fileinfo curl intl zip gd soap gmp sodium`
   and **opcache**.
3. The **command-line** PHP must also be 8.3. In cPanel → Terminal run `php -v`. If it is not 8.3, use the full path
   (commonly `/opt/cpanel/ea-php83/root/usr/bin/php`) everywhere this guide says `php`, and put it in `KAABE_PHP_BINARY`.

## 2. PHP settings (cPanel → MultiPHP INI Editor → Editor Mode → PHP 8.3 / the staging domain)

```ini
memory_limit = 512M
max_execution_time = 120
upload_max_filesize = 20M
post_max_size = 25M
opcache.enable = 1
opcache.memory_consumption = 128
opcache.validate_timestamps = 1
opcache.revalidate_freq = 2
expose_php = Off
display_errors = Off
log_errors = On
```

`opcache.revalidate_freq ≤ 2` makes a suspension visible to the POS within 2 seconds (the tenant registry is a PHP file).
The defaults `upload_max_filesize=2M / post_max_size=8M` are too small for product images and CSV imports.

## 3. MariaDB

cPanel → **General Information / Server Information**: MariaDB **10.6 or newer** (tested on 10.11).
Ask InMotion for the **database quota** of the plan (number of databases and database users). Staging needs
1 central database + 1 per test business (plan for at least 6 databases and 6 users).

## 4. Central database (staging only)

cPanel → **MySQL® Databases**:
1. *Create New Database*: `<user>_kaabe` (cPanel adds the `<user>_` prefix).
2. *Add New User*: `<user>_kaabe`, strong password (password generator) — write it down for `DB_PASSWORD`.
3. *Add User To Database*: `<user>_kaabe` → `<user>_kaabe` → **ALL PRIVILEGES**.

Never reuse a production database, user or password here.

## 5. Provisioning (one database + user per business)

On cPanel hosting, regular MariaDB users cannot create other users, so staging uses **`KAABE_PROVISIONER=cpanel`**.

1. cPanel → **Security → Manage API Tokens → Create**: name `kaabe-staging`, expiry of your choice → copy the token once.
2. The token acts as the cPanel user. Kaabe calls only these UAPI functions (all on the same server, port 2083):

   | Module / function | Purpose |
   |---|---|
   | `Mysql::list_databases`, `Mysql::create_database` | business database `<user>_tNNNNN` |
   | `Mysql::list_users`, `Mysql::create_user`, `Mysql::set_password` | business database user `<user>_tNNNNN` |
   | `Mysql::set_privileges_on_database` (ALL PRIVILEGES) | that user on that database **only** |
   | `Mysql::delete_database` | only for a failed draft that you *reset* |
   | `SubDomain::addsubdomain` (only if `KAABE_CPANEL_CREATE_SUBDOMAINS=true`) | `<slug>.<base>` → `<root>/pos` |
   | `SSL::start_autossl_check` (same condition) | request the certificate |

3. The account needs the cPanel features **MySQL Databases**, **Subdomains** and **SSL/TLS (AutoSSL)**.
4. `KAABE_DB_PREFIX` must be the cPanel prefix `<user>_`.

**Direct mode** (`KAABE_PROVISIONER=direct`) is only for VPS/dedicated servers with root MariaDB access. The exact
privileges of that provisioning account are (replace `kaabe_` by your prefix; do **not** escape the underscore):

```sql
CREATE USER 'kaabe_prov'@'localhost' IDENTIFIED BY '<strong password>';
GRANT CREATE USER ON *.* TO 'kaabe_prov'@'localhost';
GRANT ALL PRIVILEGES ON `kaabe_t%`.* TO 'kaabe_prov'@'localhost' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON `kaabe_rehearsal`.* TO 'kaabe_prov'@'localhost' WITH GRANT OPTION;
```

It gets **nothing** on the central database and nothing on production databases.

## 6. Domains, subdomains and document roots

cPanel → **Domains** (or *Subdomains* on older cPanel):

| Domain | Document root | Notes |
|---|---|---|
| `admin.<base>` | `<root>/platform/public` | Super Admin |
| business subdomains | `<root>/pos` | POS for every business |

Business subdomains — choose one:
- **Per-business (recommended for staging):** set `KAABE_CPANEL_CREATE_SUBDOMAINS=true` and `KAABE_CPANEL_POS_DOCROOT=kaabe/pos`
  (path relative to the home folder; option B: `kaabe-staging/pos`). Kaabe creates `<slug>.<base>` and requests AutoSSL when a
  business is provisioned. You can also create each one by hand with document root `<root>/pos`.
- **Wildcard:** create the subdomain `*` under `<base>` with document root `<root>/pos`. A wildcard needs a **wildcard SSL
  certificate** — AutoSSL does not always issue wildcards; ask InMotion (or buy one). Without it, use per-business subdomains.

## 7. SSL / HTTPS

1. cPanel → **SSL/TLS Status** → *Run AutoSSL* → `admin.<base>` and each business subdomain must show a valid certificate.
2. cPanel → **Domains** → turn on **Force HTTPS Redirect** for `admin.<base>` and the business subdomains.
   (Both apps also redirect HTTP → HTTPS in their `.htaccess`; cookies are `Secure`, so the sites only work over https.)

## 8. Upload and extract

1. Upload `kaabe-saas-1.0.0.zip` to `/home/<user>/` (File Manager → Upload).
2. Check it in cPanel → Terminal:
   ```bash
   cd ~ && sha256sum kaabe-saas-1.0.0.zip
   # must equal the SHA-256 published with the release (it cannot be written inside the ZIP itself)
   unzip -q kaabe-saas-1.0.0.zip && mv kaabe-saas-1.0.0 kaabe      # option B: mv kaabe-saas-1.0.0 kaabe-staging
   cd ~/kaabe && cat VERSION                                           # 1.0.0
   php scripts/check-requirements.php                                  # must end with "No FAIL"
   ```
   `platform/vendor` is included — **no Composer and no internet access are needed**.

## 9. Environment files

```bash
cd ~/kaabe
cp platform.env.example platform/.env
cp pos.env.example pos/kaabe/.env
php -r 'echo bin2hex(random_bytes(32)), PHP_EOL;'   # → KAABE_REGISTRY_KEY (same value in BOTH files)
php -r 'echo bin2hex(random_bytes(24)), PHP_EOL;'   # → KAABE_ENCRYPTION_KEY (POS only)
chmod 640 platform/.env pos/kaabe/.env
```

Edit with File Manager (or `nano`). Replace every `<cpaneluser>` by `<user>`, `<your-domain>` by `<base>`, and set:

**`platform/.env`**

| Variable | Staging value |
|---|---|
| `APP_ENV` / `APP_DEBUG` | `production` / `false` |
| `APP_URL` | `https://admin.<base>` |
| `DB_DATABASE` / `DB_USERNAME` / `DB_PASSWORD` | `<user>_kaabe` / `<user>_kaabe` / the password from §4 (in double quotes if it has `#` or spaces) |
| `KAABE_BASE_DOMAIN` | `<base>` |
| `KAABE_POS_PATH`, `KAABE_POS_SCHEMA_PATH`, `KAABE_MIGRATION_TOOLS`, `KAABE_REGISTRY_PATH` | paths under `<root>` (already correct after the replacement for `~/kaabe`) |
| `KAABE_REGISTRY_KEY` | the 64-character value |
| `KAABE_PHP_BINARY` | `php` or the full ea-php83 path (§1.3) |
| `KAABE_PROTECTED_DATABASES` | **keep** `ssgplatforms_deeq` (add any other production database names, comma-separated) |
| `KAABE_PROVISIONER` | `cpanel` |
| `KAABE_DB_PREFIX` | `<user>_` |
| `CPANEL_HOST` / `CPANEL_USER` / `CPANEL_API_TOKEN` | `https://<server hostname>:2083` (cPanel → General Information) / `<user>` / the token |
| `KAABE_CPANEL_CREATE_SUBDOMAINS` / `KAABE_CPANEL_POS_DOCROOT` | `true` / `kaabe/pos` (§6) |
| `MAIL_*` | an InMotion mailbox (SMTP) or `MAIL_MAILER=log` for staging |

**`pos/kaabe/.env`**: `KAABE_BASE_DOMAIN=<base>`, the same `KAABE_REGISTRY_KEY`, `KAABE_ENCRYPTION_KEY`, `KAABE_REGISTRY_PATH` (same path),
keep `CI_ENV=production`, `KAABE_SECURE_COOKIES=1`, `KAABE_CSRF=1`.

## 10. Install

```bash
cd ~/kaabe/platform
php artisan key:generate --force
php artisan kaabe:install          # asks the first Super Admin name, e-mail, password (≥ 12 characters, hidden)
php artisan config:cache && php artisan route:cache && php artisan view:cache
```

`kaabe:install` checks everything first and **changes nothing if a check fails**; it creates the central tables, plans and
roles, the first Super Admin, the tenant registry and an install lock (it cannot run twice).
After any later change to `platform/.env`, run `php artisan config:cache` again.

## 11. Cron (cPanel → Cron Jobs)

```text
* * * * *   cd /home/<user>/kaabe/platform && php artisan schedule:run >> /dev/null 2>&1
30 2 * * *  /bin/bash /home/<user>/kaabe/scripts/backup-all.sh >> /home/<user>/kaabe-backups.log 2>&1
```

Use the full ea-php83 path if `php` is not 8.3. The first line runs provisioning, sales sync, health checks and POS tasks.
If the plan does not allow every-minute cron, use `*/5` (provisioning and sync then take up to 5 minutes).

## 12. First Super Admin login and 2FA

1. Open `https://admin.<base>` → sign in with the account from §10.
2. You are sent to **Account security**: scan the QR/secret with an authenticator app (Google Authenticator, Microsoft
   Authenticator, Authy), enter the 6-digit code → **Enable**. 2FA is mandatory for the Super Admin.
3. Sign out and in again: the 6-digit code is asked every time.

## 13. Continue

Run `STAGING-ACCEPTANCE-CHECKLIST.md` from the top. Staging is accepted only when every line is ticked.
Do **not** run `kaabe:adopt`, `kaabe:rehearse` or `scripts/adopt-existing.sh` against any production database on staging.

## If something fails

`TROUBLESHOOTING.md` lists every problem seen during testing and its fix. The most common staging issues:
- *Business stays "pending"* → cron not running (§11).
- *"You do not have the feature mysql"* → the cPanel account/token lacks MySQL Databases (§5.3).
- *Session keeps signing out / "Page expired"* → site opened over `http://`, or `APP_URL`/`KAABE_BASE_DOMAIN` wrong (§7, §9).
- *Suspended business still works for a few seconds* → `opcache.revalidate_freq` too high (§2).
