# Kaabe SaaS POS 1.0.0 – Deployment on InMotion Hosting (cPanel)

This guide is the InMotion-specific companion of `INSTALLATION.md` (which has every command).
Items marked **VERIFY ON INMOTION** could not be tested outside your account; everything else was executed in an isolated
cPanel-like test environment (Apache + PHP 8.3 + MariaDB 10.11, HTTPS, per-minute cron, account user `kaabeuser`) – see `TESTING-REPORT.md`.

> Production protection: `ssgplatforms_deeq` is listed in `KAABE_PROTECTED_DATABASES`. Adoption of it is refused unless the
> command is given the exact phrase `PHASE 3 APPROVED — PROCEED`. Do not run adoption before that approval.

## 1. What you need on the account

| Item | Requirement | Where in cPanel |
|---|---|---|
| Plan | Shared (pilot) or VPS. Needs: SSH/Terminal, per-minute cron, ≥ 1 + (number of businesses) MariaDB databases | **VERIFY ON INMOTION** (Account Management Panel) |
| PHP version | **8.3** (8.2 minimum) for the account *and* the command line | MultiPHP Manager; Terminal `php -v` |
| PHP extensions | pdo_mysql, mysqli, openssl, mbstring, tokenizer, xml, dom, simplexml, ctype, json, bcmath, fileinfo, curl, intl, zip, gd, soap, gmp, sodium, opcache | Select PHP Version → Extensions (or MultiPHP: EasyApache 4 packages) |
| PHP INI | `memory_limit=512M`, `max_execution_time=120`, `upload_max_filesize=20M`, `post_max_size=25M`, `opcache.enable=1`, `opcache.validate_timestamps=1`, `opcache.revalidate_freq=2`, `display_errors=Off`, `expose_php=Off` | MultiPHP INI Editor (per domain: admin and POS) |
| `proc_open` | Must not be in `disable_functions` (installer, provisioning, POS cron use it) | `php scripts/check-requirements.php`; **VERIFY ON INMOTION** |
| MariaDB | **10.6 or newer** (tested on 10.11), InnoDB, utf8mb4 | `mysql --version` |
| CLI tools | mysql, mysqldump, gzip, tar, unzip, sha256sum | `check-requirements.php` |
| Composer / internet | **Not needed** – `platform/vendor` is bundled in the ZIP | – |

If `php -v` in the Terminal is not 8.3, use the EA-PHP binary everywhere (cron, `KAABE_PHP_BINARY`):
`/opt/cpanel/ea-php83/root/usr/bin/php` (**VERIFY ON INMOTION**: `ls /opt/cpanel | grep ea-php`).

## 2. Folder layout

```
/home/<cpaneluser>/
├── kaabe/                    ← the ZIP, renamed from kaabe-saas-1.0.0
│   ├── platform/public       ← document root of admin.<domain>   (Super Admin)
│   ├── pos                   ← document root of *.<domain>        (every business POS)
│   ├── private/tenants.php   ← tenant registry (written by the platform, mode 640)
│   └── scripts, migration, docs
└── kaabe-backups/            ← nightly backups (mode 700)
```

Nothing outside `platform/public` and `pos` is reachable from the web. Both `.htaccess` files deny `.env`, `.sql`, `.gz`, `.log`, `.md`
and force HTTPS (tested: `http://` → 301 to `https://`).

## 3. Domains, sub-domains and document roots

cPanel → **Domains** → *Create A New Domain* (uncheck "Share document root"):

| Domain | Document root | Purpose |
|---|---|---|
| `admin.<domain>` | `/home/<cpaneluser>/kaabe/platform/public` | Super Admin |
| `*.<domain>` (wildcard) **or** one sub-domain per business (`alpha.<domain>`, …) | `/home/<cpaneluser>/kaabe/pos` | Business POS |

- Wildcard sub-domain: needs the DNS record `*.<domain>` (A record to the account IP) and a wildcard certificate.
  AutoSSL issues wildcard certificates only when DNS is on the cPanel server / DNS-01 is possible – **VERIFY ON INMOTION**.
- Without a wildcard: set `KAABE_CPANEL_CREATE_SUBDOMAINS=true` and `KAABE_CPANEL_POS_DOCROOT=kaabe/pos`; the platform then creates
  `<slug>.<domain>` through the cPanel API during provisioning and starts an AutoSSL check (tested against a UAPI simulator).
- Unknown sub-domains, the bare domain and spoofed host names (e.g. `alpha.<domain>.evil.com`) return 404 (tested).

## 4. SSL / HTTPS

cPanel → **SSL/TLS Status** → *Run AutoSSL* for `admin.<domain>` and the business sub-domains. Then cPanel → **Domains** →
*Force HTTPS Redirect* ON for each. Cookies are `Secure` + `HttpOnly` + `SameSite` and the apps send HSTS, so the site **must** be HTTPS.

## 5. Databases

1. cPanel → **MySQL® Databases**: database `<cpaneluser>_kaabe`, user `<cpaneluser>_kaabe` (strong password), *ALL PRIVILEGES* on it.
2. Business databases are created automatically (§7) as `<cpaneluser>_t00001`, `<cpaneluser>_t00002`, … each with its own user
   that has privileges **only on its own database** (tested).

## 6. Environment files (`platform/.env`, `pos/kaabe/.env`)

Copy `platform.env.example` → `platform/.env` and `pos.env.example` → `pos/kaabe/.env`, `chmod 640` both. Key values:

| Variable | Value on InMotion |
|---|---|
| `APP_URL` | `https://admin.<domain>` |
| `APP_ENV` / `APP_DEBUG` | `production` / `false` |
| `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD` | the central database from §5 |
| `SESSION_SECURE_COOKIE` | `true` |
| `KAABE_BASE_DOMAIN` | `<domain>` (same in both files) |
| `KAABE_REGISTRY_PATH` | `/home/<cpaneluser>/kaabe/private/tenants.php` (same in both files) |
| `KAABE_REGISTRY_KEY` | 64 hex chars, `php -r 'echo bin2hex(random_bytes(32));'` – **same in both files** |
| `KAABE_ENCRYPTION_KEY` (POS) | 48 hex chars, `php -r 'echo bin2hex(random_bytes(24));'` |
| `KAABE_PHP_BINARY` | output of `command -v php` or the EA-PHP path |
| `KAABE_PROVISIONER` | `cpanel` |
| `CPANEL_HOST` / `CPANEL_USER` / `CPANEL_API_TOKEN` | `https://<server-hostname>:2083` / cPanel user / token from §7 |
| `KAABE_DB_PREFIX` | `<cpaneluser>_` |
| `KAABE_PROTECTED_DATABASES` | keep `ssgplatforms_deeq` listed |
| `MAIL_*` | your cPanel mailbox (SMTP `mail.<domain>`, port 465/587) |

Inline comments after a value (`KEY=value   # note`) are handled correctly by both apps (a bug fixed in 1.0.0).

## 7. cPanel API token (automatic provisioning)

cPanel → **Security → Manage API Tokens** → *Create*: name `kaabe`. Copy the token into `CPANEL_API_TOKEN` (it is shown once).
Kaabe calls only these UAPI functions:

| Module | Functions | Used for |
|---|---|---|
| Mysql | `list_databases`, `create_database`, `list_users`, `create_user`, `set_password`, `set_privileges_on_database` (`ALL PRIVILEGES` on the business's own database), `delete_database` (only for a failed rehearsal) | business database + user |
| SubDomain | `addsubdomain` | only if `KAABE_CPANEL_CREATE_SUBDOMAINS=true` |
| SSL | `start_autossl_check` | certificate for a new sub-domain |

Tested behaviour (UAPI simulator): missing MySQL feature → clear "You do not have the feature mysql" error, nothing created;
HTTP 500 / invalid token (401) → step fails safely and *Retry* completes it; each database is created exactly once;
the token and passwords never appear in errors or logs. **VERIFY ON INMOTION**: the token's real feature list and database quota.

## 8. Installation

Follow `INSTALLATION.md` §5–§12. In short (Terminal):

```bash
cd ~ && unzip -q kaabe-saas-1.0.0.zip && mv kaabe-saas-1.0.0 kaabe && cd kaabe
mkdir -p private && chmod 750 private
chmod -R 775 platform/storage platform/bootstrap/cache pos/application/cache pos/application/logs
php scripts/check-requirements.php
# create and fill platform/.env and pos/kaabe/.env (§6)
cd platform && php artisan key:generate --force && php artisan kaabe:install
php artisan config:cache && php artisan route:cache && php artisan view:cache
```

## 9. Cron

cPanel → **Cron Jobs** (replace the PHP path if needed):

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

The first line drives the queue (provisioning), sales sync (every 5 min), health checks, POS scheduled tasks and the nightly reconcile.
If the plan does not allow every-minute cron, use `*/5` – provisioning and sync then run up to 5 minutes later. **VERIFY ON INMOTION**.

## 10. First Super Admin login and 2FA

Open `https://admin.<domain>`, sign in with the account created by `kaabe:install`. You are sent to **Account → Security**:
scan the secret with an authenticator app (Google Authenticator, Authy, Microsoft Authenticator) and enter the 6-digit code.
Every later sign-in asks for a code. Login is limited to 10 attempts/minute, 2FA to 6/minute.

## 11. First business

Super Admin → **Businesses → Provision**: name, sub-domain, owner, plan, first branch. The job runs within a minute (cron).
Then **Users** tab → *Temporary password* for the owner → give it to the owner; the POS forces a new password at first sign-in.

## 12. Existing business adoption (after `PHASE 3 APPROVED — PROCEED` only)

1. Rehearse on a **copy** (never the live database): `php artisan kaabe:rehearse --dump=<backup.sql.gz> --owner=<username>`.
   It restores the dump into `<prefix>rehearsal`, adopts it, validates, rolls back and writes `ACCEPTANCE.md`. Tested: 54/54 measures identical after rollback.
2. Real adoption: `bash scripts/adopt-existing.sh …` (see `M7_MIGRATION_PLAN.md`). It takes a backup and a before-profile first
   and refuses the protected database without the approval phrase.

## 13. Backup

- Nightly cron (§9) → `~/kaabe-backups/<timestamp>/`: central + every business database (gzip), `.env` files, registry, `SHA256SUMS`, mode 600/700; keeps 7.
- Copy backups off the server weekly (download or InMotion backup service). Details: `BACKUP-RESTORE.md`.
- cPanel **Backup** (JetBackup on InMotion) is an additional layer – **VERIFY ON INMOTION** that it includes all `<prefix>_*` databases.

## 14. Upgrade and rollback

`bash scripts/upgrade.sh ~/kaabe-saas-<new>.zip` – backup, maintenance mode, copy of the current release to `~/kaabe-previous-<timestamp>`,
new files (including the bundled `vendor`), central and business migrations, caches, maintenance off.
`bash scripts/rollback-release.sh ~/kaabe-previous-<timestamp>` puts the previous release back; restore the database backup too if the
new release had already run migrations. See `UPGRADE.md`.

## 15. After deployment

Work through `POST-INSTALL-CHECKLIST.md`.
