# Deploying Zues on cPanel

These steps put Zues on a cPanel host with **no sample data**. You start with just the 10 expense categories and the owner account you create.

Throughout, replace `cpaneluser` with your cPanel username and `your-domain.co.tz` with your domain.

## What you need

- cPanel with **PHP 8.4.1 or newer** and a MySQL or MariaDB database.
- **Terminal** in cPanel (under Advanced) or SSH access. If you have neither, see [No Terminal?](#no-terminal).
- A domain or subdomain for the app, e.g. `app.your-domain.co.tz`.

## 1. Build the upload package (on your computer)

```bash
./deploy/build.sh
```

This makes `dist/zues-<date>.zip`, about 18 MB. It contains the app with its PHP packages and built styles. It leaves out the demo data, tests, developer tools, your local `.env` and any local receipts.

## 2. Create the database

cPanel → **MySQL® Databases**:

1. Create a database, e.g. `cpaneluser_zues`.
2. Create a user, e.g. `cpaneluser_zues`, with a strong password.
3. **Add the user to the database** and tick **ALL PRIVILEGES**.

## 3. Upload and unzip

cPanel → **File Manager**:

1. Open your **home folder** (`/home/cpaneluser`), *not* `public_html`.
2. Upload the zip, then right-click → **Extract**. You get `/home/cpaneluser/zues`.
3. Delete the zip.

Keeping the app outside `public_html` means `.env` (your passwords) and the receipt photos can never be downloaded from the web.

## 4. Point the domain at the app

**Option A (recommended).** cPanel → **Domains** → your domain → **Manage**. Set the document root to `zues/public`.

**Option B (if you can't change the document root, e.g. the main domain on some hosts):**

1. Copy everything inside `zues/public`, including the hidden `.htaccess`, into `public_html`.
2. Replace `public_html/index.php` with `zues/deploy/public_html/index.php`.

That file expects the app in `/home/cpaneluser/zues`.

## 5. Choose PHP 8.4

- cPanel → **MultiPHP Manager** → tick your domain → **PHP 8.4** (or newer) → Apply.
- cPanel → **Select PHP Version** → **Extensions**, if your host has this page. Make sure these are on: `pdo_mysql`, `mbstring`, `gd`, `zip`, `dom`, `xml`, `fileinfo`, `intl`.

The Terminal may use a different PHP than the website. Check with `php -v`. If it's older than 8.4, use the full path in every command below. It is usually `/usr/local/bin/ea-php84` (instead of `php`), or `/opt/cpanel/ea-php84/root/usr/bin/php`.

## 6. Settings (`.env`)

In File Manager, open `zues`. Turn on **Settings → Show Hidden Files** first. Copy `.env.example` to `.env`, then edit `.env`:

```dotenv
APP_URL=https://app.your-domain.co.tz
DB_DATABASE=cpaneluser_zues
DB_USERNAME=cpaneluser_zues
DB_PASSWORD=the-database-password
```

Leave `APP_DEBUG=false`. The app key is filled in next.

## 7. Set up the database (Terminal)

```bash
cd ~/zues
php artisan key:generate --force     # once only: creates APP_KEY
php artisan migrate --force          # creates the tables
php artisan db:seed --force          # adds the 10 expense categories, nothing else
php artisan app:create-owner         # asks for your name, email and password
php artisan optimize                 # speeds the app up
php artisan app:doctor               # checks everything; should end with "Ready."
```

You may see this during `migrate`: *"Database triggers were not created … binary logging is on"*. That's fine. Many cPanel hosts don't allow database triggers. The app still refuses double-bookings itself: it locks the room while saving, and that was tested with two simultaneous bookings. If you want the extra database-level protection, ask your host to set `log_bin_trust_function_creators = 1`, then run `php artisan app:install-triggers`.

### Or: import the ready-made database (no Terminal, no commands)

Use this instead of step 7. The file `deploy/database/zues-database.sql` (also in the zip, at `zues/deploy/database/`) is a ready-made empty database containing:

- every table;
- the 10 expense categories;
- one admin (owner) account, which must choose a new password at first sign-in:

  | Email | Password |
  |---|---|
  | `admin@example.com` | `ChangeMe-2026` |

There's no sample data.

1. **App key:** on your computer, run `php artisan key:generate --show` and paste the result into `APP_KEY=` in the server's `.env`.
2. cPanel → **phpMyAdmin** → click your database on the left (it must be empty) → **Import** → choose `zues-database.sql` → **Import**.
3. *Optional:* import `zues-triggers-optional.sql` the same way. It adds the database-level double-booking protection. If it fails with **#1419 … SUPER privilege**, your host doesn't allow triggers. That's fine: the app refuses double-bookings itself.
4. **Sign in straight away** as `admin@example.com` / `ChangeMe-2026`. The password is public until you change it, so don't leave the site waiting. Choose your own password, then go to **Users** and change the admin's name and email to yours.

To build the file with your own admin email and password instead, run this on your computer:

```bash
./deploy/make-database-sql.sh you@your-domain.co.tz 'Your-temporary-pass-1'
```

If you rerun it after future changes to the app, the import file stays up to date.

## 8. Daily jobs (Cron)

This creates the recurring expenses, such as monthly internet or salaries. cPanel → **Cron Jobs** → add, with the **Once Per Minute** setting:

```
cd /home/cpaneluser/zues && /usr/local/bin/ea-php84 artisan schedule:run >> /dev/null 2>&1
```

## 9. HTTPS

cPanel → **SSL/TLS Status** → run **AutoSSL** for the domain. Then cPanel → **Domains** → turn on **Force HTTPS Redirect**. Keep `SESSION_SECURE_COOKIE=true` in `.env`; it needs HTTPS to work.

## 10. Start using it

Open `https://app.your-domain.co.tz`, sign in as the owner, then:

1. **Properties** → add each property and its rooms with nightly rates.
2. **Users** → invite managers and staff, choose their roles, and tick their properties.
3. Start entering bookings from the **Calendar**.

## Backups

Back up these three things regularly. cPanel → **Backup** can download the database and your home folder.

- the **database**;
- `zues/storage/app/private/receipts`, the receipt photos;
- `zues/.env`. Without its `APP_KEY`, existing sign-ins stop working.

## Updating to a new version

```bash
cd ~
php zues/artisan down                         # show a maintenance page
mv zues zues_old
unzip zues-<new-date>.zip                     # creates a fresh zues/
cp zues_old/.env zues/.env
cp -R zues_old/storage/app/private/. zues/storage/app/private/
cd zues
php artisan migrate --force
php artisan optimize
php artisan up
```

If you used Option B, also copy the new `zues/public/build` folder into `public_html/build`. Delete `zues_old` once everything works.

## No Terminal?

Use a temporary cron job to run the setup commands once:

1. Generate an app key on your computer with `php artisan key:generate --show` and paste it into `APP_KEY=` in the server's `.env`.
2. cPanel → **Cron Jobs** → add a **Once Per Minute** job:

   ```
   cd /home/cpaneluser/zues && ( /usr/local/bin/ea-php84 artisan migrate --force; /usr/local/bin/ea-php84 artisan db:seed --force; /usr/local/bin/ea-php84 artisan app:create-owner --name="Your Name" --email="you@example.com" --password="Temporary-pass-1"; /usr/local/bin/ea-php84 artisan optimize; /usr/local/bin/ea-php84 artisan app:doctor ) >> /home/cpaneluser/zues/storage/logs/setup.log 2>&1
   ```

3. Wait two minutes, then open `zues/storage/logs/setup.log`. It should end with "Ready." From the second run on it also says the owner already exists; that's expected.
4. **Delete that cron job.** It contains a password. Because of that, the app makes you choose a new password the first time you sign in.

## Troubleshooting

| You see | Do this |
|---|---|
| "500 Server Error" | Read `zues/storage/logs/laravel.log`. Run `php artisan app:doctor`. |
| "Your Composer dependencies require a PHP version >= 8.4.1" | Switch the domain to PHP 8.4 (step 5), and use the 8.4 path in Terminal and cron. |
| The page has no styling, or "Vite manifest not found" | With Option B, you missed copying `public/build` or replacing `index.php`. |
| "419 Page Expired" when signing in | `APP_URL` must match the address in the browser. `SESSION_SECURE_COOKIE=true` needs `https://`. |
| "Permission denied" writing logs | Set folders `zues/storage` and `zues/bootstrap/cache` (and their contents) to 755. |
| You forgot the owner password | `php artisan app:create-owner` makes another owner. That owner can reset anyone's password under Users. |
