# Kaabe SaaS POS – Installation

**Version:** see `VERSION` (1.0.0-rc.1, a release candidate).

This guide is for a technical user who can use cPanel and paste commands into a terminal. The InMotion-specific screens are described in `DEPLOYMENT-INMOTION-CPANEL.md`; this file is the complete sequence.

> **Status:** none of these steps has been executed by the developer yet, because the build environment has no PHP or MariaDB. They were written from the code and checked statically. Every step prints a clear error if something is wrong, and nothing is changed until the checks pass. Report any error message and it will be fixed.

## What gets installed

| Part | Folder | Web address | Purpose |
|---|---|---|---|
| Super Admin | `kaabe/platform` (web root: `kaabe/platform/public`) | `https://admin.<your-domain>` | Businesses, plans, subscriptions, payments, monitoring |
| Business POS | `kaabe/pos` (web root: `kaabe/pos`) | `https://<business>.<your-domain>` | The PHP POS, one database per business |
| Private data | `kaabe/private` | – (never web-accessible) | Tenant registry (encrypted database passwords) |
| Tools | `kaabe/scripts`, `kaabe/migration` | – | Install, backup, upgrade, rehearsal, adoption |

## 1. Server requirements

Run this after uploading (step 5). It changes nothing:

```bash
php scripts/check-requirements.php
```

| Requirement | Value | How to check / set |
|---|---|---|
| PHP (web and command line) | 8.2 or 8.3 (8.3 recommended) | cPanel → MultiPHP Manager; `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 | cPanel → Select PHP Version → Extensions |
| PHP settings | memory_limit ≥ 256M (512M recommended), max_execution_time 120 (web), upload_max_filesize ≥ 20M, post_max_size ≥ 25M (the PHP defaults 2M/8M are too small for imports and images), opcache.enable = 1, opcache.validate_timestamps = 1, opcache.revalidate_freq ≤ 2 (the tenant registry is a PHP file that changes when a business is suspended) | cPanel → MultiPHP INI Editor |
| `proc_open` allowed | Needed by the installer, provisioning and POS cron | `check-requirements.php`; **VERIFY ON INMOTION** |
| MariaDB | 10.6 or newer | `mysql --version`; **VERIFY ON INMOTION** |
| Command-line tools | mysql, mysqldump, gzip, tar, unzip, sha256sum. **Composer is NOT needed** – the ZIP ships the Super Admin's PHP libraries in `platform/vendor` | `check-requirements.php` |
| SSH / Terminal access | Needed once to install (cPanel → Terminal is enough) | cPanel → Terminal, or SSH |
| Outbound HTTPS | **Not needed** for installation or upgrades (libraries are bundled). Only the cPanel API (`https://<server>:2083`, same server) is called for automatic provisioning | – |
| Cron | Every minute | cPanel → Cron Jobs; **VERIFY ON INMOTION** (some shared plans limit frequency) |
| Disk | Code ≈ 400 MB, plus databases, plus 7 nightly backups | cPanel → Disk Usage |
| Databases | 1 central + 1 per business (plus 1 temporary for a rehearsal) | `uapi StatsBar get_stats display=mysqldatabases`; **VERIFY ON INMOTION** |

## 2. Create the central database

In cPanel → **MySQL® Databases** → *Create New Database*, name it `kaabe`. cPanel shows the full name, e.g. `<cpaneluser>_kaabe`.

## 3. Create the database user

Same page → *Add New User*: user `kaabe`, with a generated strong password. Save the password in your password manager.

## 4. Assign privileges

Same page → *Add User To Database*: user `<cpaneluser>_kaabe` → database `<cpaneluser>_kaabe` → **ALL PRIVILEGES**.

### 4b. Provisioning account (only if you use automatic provisioning)

Kaabe creates one database + one database user per business. Choose ONE method in `platform/.env`:

**A. `KAABE_PROVISIONER=cpanel` (recommended on InMotion shared/cPanel).** cPanel → **Manage API Tokens** → *Create* a token (name `kaabe`, no expiry or a long one). Put it in `CPANEL_API_TOKEN`, your cPanel user in `CPANEL_USER`, `CPANEL_HOST=https://<server-hostname>:2083`, and `KAABE_DB_PREFIX=<cpaneluser>_`. The token acts as your cPanel account, so it can only use the **MySQL Databases** feature (create/list databases and users, set privileges), **Subdomains** (if `KAABE_CPANEL_CREATE_SUBDOMAINS=true`) and **SSL/AutoSSL**. Keep it only in `platform/.env` (mode 640). Tested against a UAPI simulator; **VERIFY ON INMOTION** with the real token.

**B. `KAABE_PROVISIONER=direct` (VPS/dedicated with root MariaDB access).** Create a dedicated MariaDB account with exactly these privileges – nothing on the central database:

```sql
CREATE USER 'kaabe_prov'@'localhost' IDENTIFIED BY '<strong password>';
GRANT CREATE USER ON *.* TO 'kaabe_prov'@'localhost';                                   -- create one user per business
GRANT ALL PRIVILEGES ON `kaabe_t%`.* TO 'kaabe_prov'@'localhost' WITH GRANT OPTION;        -- business databases kaabe_t00001…
GRANT ALL PRIVILEGES ON `kaabe_rehearsal`.* TO 'kaabe_prov'@'localhost' WITH GRANT OPTION;  -- adoption rehearsal database
```

Replace `kaabe_` with your `KAABE_DB_PREFIX`. **Do not escape the underscore** (`kaabe\_t%`): MariaDB then refuses the per-business `GRANT` with *Access denied* (tested on MariaDB 10.11). The unescaped pattern was tested: it covers the business databases and the rehearsal database, and the account still has **no access to the central database** (`SELECT` on it is denied). If provisioning stops at the grant step with "Access denied", fix the grant and press *Retry*.

## 5. Upload the ZIP

cPanel → **File Manager** → your home folder (`/home/<cpaneluser>`, **not** `public_html`) → *Upload* `kaabe-saas-<version>.zip`.

## 6. Extract

Right-click the ZIP → *Extract* into `/home/<cpaneluser>`. Then rename the folder `kaabe-saas-<version>` to `kaabe`. In the Terminal:

```bash
cd ~ && unzip -q kaabe-saas-*.zip && mv kaabe-saas-* kaabe && cd kaabe
mkdir -p private && chmod 750 private
chmod -R 775 platform/storage platform/bootstrap/cache
chmod -R 775 pos/application/cache pos/application/logs
php scripts/check-requirements.php
```

## 7. Configure the document roots

In cPanel → **Domains**:

| Create | Document root |
|---|---|
| `admin.<your-domain>` | `/home/<cpaneluser>/kaabe/platform/public` |
| Each business: `<business>.<your-domain>`, or once `*.<your-domain>` (wildcard) | `/home/<cpaneluser>/kaabe/pos` |

Details and SSL are in `DEPLOYMENT-INMOTION-CPANEL.md` §3.

## 8. Configure the 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;'    # use for KAABE_REGISTRY_KEY (same in BOTH files)
php -r 'echo bin2hex(random_bytes(24)), PHP_EOL;'    # use for KAABE_ENCRYPTION_KEY (POS)
nano platform/.env                                   # or edit in File Manager
nano pos/kaabe/.env
chmod 640 platform/.env pos/kaabe/.env
```

Fill every `<...>` value. The two files must share the same `KAABE_REGISTRY_KEY` and `KAABE_BASE_DOMAIN`.

## 9. Build and install

```bash
cd ~/kaabe
cd platform                                         # platform/vendor is bundled – no composer, no internet needed
php artisan key:generate --force
php artisan kaabe:install                           # checks → central tables → plans → first Super Admin → registry
php artisan config:cache && php artisan route:cache && php artisan view:cache
```

`kaabe:install`:
- checks PHP, extensions, `.env`, folders, the POS path, the command-line tools and the database connection;
- **changes nothing if a check fails**;
- creates the central tables and loads the roles, permissions, modules, limits and the Free/Basic/Professional/Enterprise plans;
- asks for the **first Super Admin** (name, e-mail and a password of at least 12 characters, typed hidden);
- writes the tenant registry;
- creates `platform/storage/app/kaabe-installed.lock` so it **cannot run twice**.

There is no web installer, so nothing is left exposed.

## 10. Create the Super Admin

This is done by step 9. To add more staff later: Super Admin → **Staff**.

## 11. Storage

Everything the Super Admin writes lives in `platform/storage` (logs, cache, sessions, rehearsal and adoption reports). The POS stores uploads **in each business's database**. `private/` holds only the registry.

## 12. Permissions (summary)

| Path | Mode |
|---|---|
| `platform/storage`, `platform/bootstrap/cache` | 775 |
| `pos/application/cache`, `pos/application/logs` | 775 |
| `private/` | 750 |
| `private/tenants.php` | 640 (written by the platform) |
| `platform/.env`, `pos/kaabe/.env` | 640 |
| Everything else | 644 files / 755 folders |

The PHP files run as your cPanel user (standard on cPanel with PHP-FPM or suPHP; **VERIFY ON INMOTION**).

## 13. Cron

cPanel → **Cron Jobs** → add both jobs. Replace `/usr/local/bin/php` with the output of `command -v php` if it differs.

```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 job runs everything else from the scheduler:

| Job | Schedule |
|---|---|
| Queue worker | Every minute |
| Sales sync | Every 5 minutes |
| Health checks and alerts | Every 15 minutes |
| POS e-commerce task | Every 15 minutes |
| POS report e-mails | Hourly |
| Expiry and entitlement re-push | Daily |
| POS recurring payments | Daily, 03:15 |
| Sales reconciliation | Nightly, 02:30 |

## 14. HTTPS

cPanel → **SSL/TLS Status** → *Run AutoSSL* for `admin.<your-domain>` and each business sub-domain. Then open `https://admin.<your-domain>`. Session cookies are HTTPS-only (`SESSION_SECURE_COOKIE=true`).

## 15. Test the installation

```bash
cd ~/kaabe/platform
php artisan kaabe:health      # every connected business: database and schema
php artisan schedule:list     # the scheduled jobs
php artisan about             # PHP, environment, drivers
```

Open `https://admin.<your-domain>` and sign in. Two-factor sign-in (TOTP) must be set up at the first login.

## 16–18. First business, branch and user

1. **Business.** Super Admin → **Businesses → New business (automatic)**. Enter the name, sub-domain, plan, owner and first branch, then *Create and provision*. The page shows each step:
   - Database created
   - Schema installed
   - Migrations completed
   - Owner created
   - Branch created
   - API key created
   - Sub-domain
   - Plan assigned
   - Ready → Active

   With `KAABE_PROVISIONER=cpanel`, the database and user are created through your cPanel API token.
2. **Sub-domain.** Unless you use the wildcard or `KAABE_CPANEL_CREATE_SUBDOMAINS=true`, create `<business>.<your-domain>` in cPanel → Domains (document root `kaabe/pos`) and run AutoSSL.
3. **Owner's first password.** Business → **Users** → owner → *Temporary password*. It is shown once; the owner changes it at first sign-in.
4. **More branches.** Business → **Branches** → *Add branch*. The plan limit is enforced.
5. **More users.** Business → **Users** → *Add user*, with a role (Cashier, Branch Manager, …). The plan limit is enforced.

## 19. Verify the POS

Open `https://<business>.<your-domain>` and sign in as the owner. Then check:
1. The business dashboard opens.
2. Create a product with stock.
3. Make a sale.
4. Stock goes down and the dashboard updates.
5. The report shows the sale.

## 20–22. Verify SaaS management, subscription and sync

Follow `POST-INSTALL-CHECKLIST.md`. It covers plan changes, module gates, suspension, payments, expiry, sync and alerts.

## 23. Production security checklist

See `SECURITY.md` §Checklist. At minimum, before going live:
- `APP_DEBUG=false`
- HTTPS on every domain
- 2FA for all staff
- `.env` files at 640
- `private/` at 750
- the backup cron running
- a first backup downloaded off the server

## Existing businesses (e.g. `ssgplatforms_deeq`)

These are **adopted in place**, never re-created. The process is in `docs/MIGRATION-ADOPTION.md`:
1. **Rehearsal (automatic).** `php artisan kaabe:rehearse --dump=<backup.sql.gz> --owner=<username>` restores a backup into a separate temporary database and runs every validation.
2. **Adoption, only after approval.** `scripts/adopt-existing.sh` is guarded by the exact approval phrase.

The live database is never touched until **PHASE 3 APPROVED — PROCEED**.
