# Runbook: install, upgrade, maintenance

Commands are run from the project folder on the server as the account that owns the site (not root). Everything here was written alongside tested code, but **the full `install` has not been run on a real server yet**: do it on a staging copy first and correct this document with what you find.

## Before the first install
1. PHP 8.4+ with `pdo_mysql`, `sodium`, `mbstring`, `intl`, `zip`, `gd`, `curl`, `fileinfo`; MariaDB 11.4 or 11.8 LTS. `php cron/cli.php diagnose` lists anything missing.
2. Create the database and three accounts (app, migrator, maintenance; optionally a backup account) in WHM/cPanel. The migrator needs `ALL PRIVILEGES` **with grant option** on the application database, because the installer applies the least-privilege grants. If your host cannot give it grant option, run `grants:apply` with a privileged account instead.
3. Create a second, empty database for restore tests and give the migrator full rights on it.
4. Copy `.env.example` to `.env`, fill it in, `chmod 600 .env`. Point the domain's document root at `public/`.
5. `composer install --no-dev` somewhere that has Composer and upload `vendor/` (Composer is not needed on the host).

## Install, the easy way: the setup page
1. Upload the project (with `vendor/`) and point the domain's document root at `public/`.
2. In cPanel > MySQL Databases, create a database and a user with all privileges on it.
3. Open `https://your-site/install.php`. It checks the server, then asks for the site address, the database details and the first administrator's email.
4. It tests each database login before changing anything, saves `.env`, builds the database and shows the administrator password and authenticator key **once**.
5. **Delete `public/install.php`.** Once installed it answers "not found" and does nothing, but there is no reason to leave it.

One database user is enough for a basic setup. In that case least-privilege protection is not applied (the page says so); split the accounts later and run `php cron/cli.php grants:apply`. The setup page has been run end to end against a scratch MariaDB (bad password, bad token and bad email are refused; a real install succeeded and the page then disappeared); it has not been run on a real cPanel host.

## Install from the command line instead
```
php cron/cli.php install you@example.com
```
It checks the server, creates `storage/` folders and the master key, builds the schema, applies grants, loads presets and the default theme, creates the first platform administrator, and writes `storage/installed.lock`. The administrator's password and authenticator key are printed **once**.

Then:
- Back up `keys/master.key` **offline**, apart from database backups. Without it encrypted data cannot be read.
- Add the cron entry the installer prints (every minute).
- `php cron/cli.php backup:run`, then `php cron/cli.php backup:verify`. Do not go live until the restore test passes.
- `php cron/cli.php backup:key` and store that key offline too.

## Upgrade
```
php cron/cli.php upgrade
```
Maintenance mode on → backup (the upgrade stops if it fails) → migrations → grants → presets/theme → maintenance off. While on, every page answers 503 with `Retry-After`; `/health` still answers.

If a step fails, maintenance mode **stays on** on purpose. Fix the cause and run `upgrade` again. If data may be damaged, restore the pre-upgrade backup into a **new** database (`backup:restore <archive> <new database>`), check it, then point `DB_NAME` at it, run `grants:apply`, and `maintenance:off`. Restore never writes into the live database.

## Other commands
`maintenance:on` / `maintenance:off` · `grants:apply` (after any migration run by hand) · `migrate` · `diagnose` · `backup:list` · `backup:prune` · `presets:sync` · `assets:build` · `demo:seed` (refuses when `APP_ENV=production`).
