# Installing Frontio (Laravel version) on cPanel hosting

This guide installs the Laravel version on a shared host with cPanel. Do it on a **test subdomain first**
(for example `test.yourdomain.com`), check it, and only then move the live site. Never point the live site at it
until you have confirmed the conversion.

Before you start, send your host the questions at the end of this guide.

---

## 1. What the host needs

- **PHP 8.3 or newer** (8.4 or 8.5 preferred). In cPanel: *Select PHP Version* or *MultiPHP Manager*.
- **PHP extensions**: BCMath, Ctype, cURL, DOM, EXIF, Fileinfo, Filter, GD (with JPEG, PNG and WebP), Hash, Intl,
  Mbstring, OpenSSL, PCRE, PDO MySQL, Session, Tokenizer, XML, Zip.
- **MySQL 8 or MariaDB 10.6** or newer, and permission to create a database and a database user.
- **Cron jobs** (ideally every minute; every 5 or 15 minutes also works, see step 8).
- **Upload limits** of at least 100 MB (`upload_max_filesize` and `post_max_size`) for course zips.
- **HTTPS** (AutoSSL or Let's Encrypt).

## 2. Build the files on your computer

On your computer, in `C:\xampp\htdocs\frontio`:

```
composer install --no-dev --optimize-autoloader
```

This makes the `vendor` folder with exactly the libraries the app needs (Laravel and mews/purifier). If the host
has SSH or the cPanel Terminal with Composer, you can run the same command there instead.

Then make a zip of the whole folder **except**:
- `.env` (your computer's settings, with its passwords)
- `storage/app/private` (your computer's test files)
- `storage/logs`, `storage/framework/cache`, `storage/framework/sessions`, `storage/framework/views`
- `tests`, `tools`, `node_modules` (if any)

## 3. Upload and place the files

1. In cPanel *File Manager*, upload the zip to your home folder, for example `/home/YOURUSER/`, and extract it
   into `/home/YOURUSER/frontio`. This folder must **not** be inside `public_html`.
2. Point the domain at the `public` folder:
   - In cPanel *Domains* (or *Subdomains*), set the **Document Root** of the domain or subdomain to
     `/home/YOURUSER/frontio/public`.
   - Only the `public` folder can be reached from the web. Everything else (settings, private files, course
     files, certificate photos) stays out of reach, as security rule 10 requires.

## 4. Create the database

1. In cPanel *MySQL Databases*: create a database (for example `YOURUSER_frontio`) and a user with a long random
   password, and add the user to the database with **All privileges**.
2. Write the names and password down for step 5. Don't send them by email.

## 5. The settings file (.env)

In `/home/YOURUSER/frontio`, copy `.env.example` to `.env` and edit it in File Manager:

```
APP_NAME=Frontio
APP_ENV=production
APP_DEBUG=false
APP_URL=https://test.yourdomain.com
APP_TIMEZONE=America/Vancouver

DB_HOST=localhost
DB_DATABASE=YOURUSER_frontio
DB_USERNAME=YOURUSER_frontiouser
DB_PASSWORD=(the password from step 4)

SESSION_SECURE_COOKIE=true

# Each organization on its own address, for example https://coastline.frontio.ca (see section 7a). APP_URL is then
# the main address (https://frontio.ca), where the owner and partners sign in. Leave TENANT_MODE out to use
# https://frontio.ca/coastline instead.
TENANT_MODE=subdomain
ROOT_DOMAIN=frontio.ca
SESSION_DOMAIN=.frontio.ca

# Emails through the host's mail server (ask the host for these):
MAIL_MAILER=smtp
MAIL_HOST=mail.yourdomain.com
MAIL_PORT=465
MAIL_SCHEME=smtps
MAIL_USERNAME=no-reply@yourdomain.com
MAIL_PASSWORD=(the mailbox password)
MAIL_FROM_ADDRESS=no-reply@yourdomain.com
FRONTIO_MAIL_MODE=mail

# Texts through Twilio (leave empty until you have an account):
TWILIO_SID=
TWILIO_TOKEN=
TWILIO_FROM=

# Never on the live site:
FRONTIO_DEV_INBOX=false
FRONTIO_DEV_SHOW_CODES=false

# Two-step sign-in for the owner, partners and administrators: always on for the live site (true). People of
# Demo organizations sign in with their password only. Set to false only on a developer's own computer.
FRONTIO_TWO_STEP=true

# When moving from the PHP build: its secret (from its app/config.php, "app_secret"), so remembered phones and
# sign-in links keep working.
LEGACY_APP_SECRET=
```

Then, in the cPanel Terminal (or SSH), in `/home/YOURUSER/frontio`:

```
php artisan key:generate
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
```

`key:generate` makes the app's own secret key. `migrate` creates all the tables.

**No Terminal?** Ask the host to run these once, or add each as a one-time cron job (step 8) and remove it after
it has run.

## 6. Folder permissions

`storage` and `bootstrap/cache` must be writable by PHP. In File Manager, set them (and the folders inside) to
`755`. Files inside them can be `644`.

## 7. HTTPS

In cPanel *SSL/TLS Status*, make sure the domain has a certificate (AutoSSL), and turn on *Force HTTPS Redirect* in
*Domains*. The app also tells browsers to always use HTTPS once they have visited.

## 7a. An address for each organization (coastline.frontio.ca)

With `TENANT_MODE=subdomain`, every organization opens at its own address, made from the web address set in the
owner console (for example `coastline` gives https://coastline.frontio.ca). The owner and partners sign in at
https://frontio.ca. Old links such as https://frontio.ca/coastline/... forward to the new address automatically, so
printed QR codes, texts and emails keep working. Three things are needed once, in cPanel:

1. **Wildcard subdomain.** In *Domains*, create the domain `*.frontio.ca` with the same document root as
   `frontio.ca` (the `public` folder of Frontio). Some hosts call this a "wildcard subdomain".
2. **Wildcard DNS.** In *Zone Editor*, make sure there is an `A` record for `*.frontio.ca` pointing to the same IP
   address as `frontio.ca` (cPanel usually adds it with step 1).
3. **Wildcard certificate.** In *SSL/TLS Status*, run AutoSSL and check that `*.frontio.ca` is covered. AutoSSL can
   only issue a wildcard certificate when the domain uses the host's name servers; if it can't, ask the host (see
   question 12 below).

Then check: https://frontio.ca/login shows the Frontio sign-in page, https://coastline.frontio.ca/login shows
Coastline's, and https://frontio.ca/coastline/login forwards to https://coastline.frontio.ca/login.

## 8. Scheduled jobs (one cron line)

In cPanel *Cron Jobs*, add:

```
* * * * * cd /home/YOURUSER/frontio && /usr/local/bin/php artisan schedule:run >> /dev/null 2>&1
```

(Ask the host for the exact path to PHP 8.3 or newer if `/usr/local/bin/php` is an older version.)

Laravel then runs the daily job every morning at 7:00: reminders, renewals, checklist reminders, retention,
the monthly link check, How-to review reminders, the summary emails and tidying. If the host only allows every
5 or 15 minutes, use `*/5` or `*/15` instead of the first `*`; the job still runs once a day.

The owner console warns you if the daily job hasn't run for more than a day.

## 9. Moving the data from the PHP build (only when you go live)

Do this at a quiet time, after a backup of the PHP build's database and files.

1. In cPanel *phpMyAdmin*, export the PHP build's database, and import it into a new database
   (for example `YOURUSER_frontio_copy`). Give the Laravel database user **read-only** access to it
   (SELECT and REFERENCES only).
2. Upload the PHP build's `storage/uploads` and `storage/courses` folders to a private folder, for example
   `/home/YOURUSER/old-storage/`.
3. Add to `.env`:
   ```
   LEGACY_DB_DATABASE=YOURUSER_frontio_copy
   LEGACY_STORAGE=/home/YOURUSER/old-storage
   ```
4. Run:
   ```
   php artisan frontio:compare-structure
   php artisan frontio:copy-old-data
   ```
   The first should say "62 of 62 tables match". The second copies everything and ends with
   "Everything matches." If it doesn't, nothing is lost: the PHP build still has all the data.
5. Staff sign in once more (sessions don't move across). Employees' phones stay confirmed.

## 10. Backups and a restore test

- Turn on the host's daily backups (cPanel *Backup* or *JetBackup*), covering the database and
  `/home/YOURUSER/frontio/storage/app/private`.
- **Test a restore**, don't assume it works (security rule 12): restore the database backup into a spare database,
  point a test copy of the app at it, and check that you can sign in and see the records.

## 11. Check it works

- Open the site: the sign-in page shows the Frontio look.
- Sign in as the owner, open an organization, open an employee.
- Send yourself a test reminder and check it arrives.
- The next morning, check the owner console shows no "Scheduled jobs haven't run" warning.

---

## Questions to send to your web host

1. Which PHP versions can I choose for my site? I need PHP 8.3 or newer (8.4 or 8.5 preferred).
2. Are these PHP extensions available: BCMath, Ctype, cURL, DOM, Fileinfo, Filter, GD (with JPEG, PNG and WebP),
   Hash, Intl, Mbstring, OpenSSL, PCRE, PDO with MySQL, Session, Tokenizer, XML, Zip and EXIF?
3. Do I have SSH or the cPanel Terminal, and is Composer installed? If not, can I run `php` from a cron job?
4. Can I set a domain's or subdomain's document root to a folder inside my account (for example
   `/home/USER/frontio/public`)?
5. Can cron jobs run every minute? If not, what's the shortest interval?
6. Which MySQL or MariaDB version do you provide, and can I create several databases and users?
7. What are the limits on outgoing emails per hour, and which SMTP settings should I use?
8. Are outgoing web connections from PHP allowed (needed for Twilio texts and the monthly link check)?
9. What are the upload size limits (`upload_max_filesize`, `post_max_size`) and can I raise them to 100 MB for
   course zips?
10. Is a free SSL certificate (Let's Encrypt or AutoSSL) included, and can I force HTTPS?
11. How often are backups made, how long are they kept, and how do I restore one?
12. Can I have a wildcard subdomain (`*.frontio.ca`) pointing to the same folder as the main domain, with a wildcard
    SSL certificate covering it?
12. Is there a staging or test subdomain I can use before going live?
