# SchoolPlus — cPanel Deployment Guide

This guide walks you through putting this application on a normal cPanel shared
hosting account, from an empty hosting account to a working, logged-in school
system. It assumes you are **not** an advanced Laravel developer. Every step
says exactly what to click or type.

If your host gives you a **Terminal** (look for "Terminal" in cPanel, under
"Advanced"), steps marked **[Terminal]** are much faster. If you don't have
one, every step also has a **[No Terminal]** alternative using cPanel's own
screens.

> **Do this on a test/staging copy first if at all possible.** Nothing in this
> guide is reversible once real families are using the real system.

---

## Before you start — what you need

- cPanel login details from your host
- A domain or subdomain pointed at the hosting account (your host or domain
  registrar can do this — ask them if you're not sure)
- The project files, either as the zip I've been giving you, or from your own
  copy of the repository
- About an hour, uninterrupted

---

## Step 1 — Check your PHP version

This application needs **PHP 7.2 or newer** (everything in this project has
been written and tested against **PHP 8.3**, so if your host offers 8.3,
8.2 or 8.1, pick that).

1. In cPanel, find **"Select PHP Version"** (sometimes called "MultiPHP
   Manager").
2. Choose **8.3** (or the newest 8.x your host offers) for your domain.
3. While you're on this screen, make sure these extensions have a checkmark
   next to them — the app won't run without them:
   `bcmath`, `ctype`, `fileinfo`, `json`, `mbstring`, `openssl`, `pdo`,
   `pdo_mysql`, `tokenizer`, `xml`, `curl`, `gd`
   (Most hosts turn all of these on by default — just glance down the list.)

---

## Step 2 — Create the MySQL database

1. In cPanel, open **"MySQL® Databases"**.
2. Under "Create New Database", type a name, e.g. `smsdb`, and click
   **Create Database**.
   - cPanel will usually show it on screen as something like
     `yourcpanelusername_smsdb`. That full name — **including the prefix** —
     is what you'll use everywhere below.

---

## Step 3 — Create a database user

Still on the same "MySQL® Databases" page:

1. Under "MySQL Users" → "Add New User", type a username, e.g. `smsuser`,
   and a **strong password**. Click **Create User**.
   - It will become something like `yourcpanelusername_smsuser`.
2. Write the username and password down somewhere safe — you'll need them in
   Step 8.

---

## Step 4 — Assign the user to the database

Still on the same page:

1. Under "Add User to Database", choose the user and database you just made,
   click **Add**.
2. On the permissions screen, check **"ALL PRIVILEGES"**, then click
   **Make Changes**.

---

## Step 5 — Upload the application files

**[Terminal]**
```
cd ~
git clone <your repository URL> sms-temp
# or: upload and unzip the zip file I gave you into sms-temp
```

**[No Terminal]**
1. On your own computer, make a zip of the whole project folder (the one
   containing `app`, `routes`, `composer.json`, etc).
2. In cPanel, open **"File Manager"**.
3. Go one level **above** `public_html` (usually the account's home
   directory).
4. Click **Upload**, and upload your zip there (not yet inside
   `public_html`).
5. Once uploaded, right-click the zip → **Extract**. You should now have a
   folder like `Laravel-SMS-master`.

> **Why not extract directly into `public_html`?** Because most of this
> project (`app/`, `routes/`, your `.env`, etc.) must **not** be reachable by
> a web browser — only the files inside the project's `public/` folder
> should be. Step 6 explains exactly how to wire that up safely.

---

## Step 6 — Point your domain at the right folder

This is the one genuinely different step compared to most PHP apps, so read
it carefully. Laravel expects visitors to land inside the project's
`public/` folder, not the project's top-level folder.

### Method A — you can add a subdomain or addon domain (recommended)

If your domain can be a **subdomain or addon domain** pointed at this app
(e.g. `portal.yourschool.com`, or this is the only site on the account):

1. In cPanel, open **"Subdomains"** (or **"Addon Domains"** if this is a
   completely separate domain).
2. Create the subdomain/domain, and when asked for the **Document Root**,
   point it directly at:
   ```
   /home/yourcpanelusername/sms-temp/public
   ```
   (adjust the path to wherever you placed the project folder in Step 5, and
   add `/public` on the end).
3. Done — skip to Step 7.

### Method B — this must be your main domain, and you can't change its document root

Some hosts only let the **main domain** point at `public_html`, with no way
to change that. If that's your situation:

1. Move (not copy) **everything inside** the project's `public/` folder up
   into `public_html`. In File Manager, open `sms-temp/public`, select all
   files/folders inside it, and use **Move** to move them into
   `public_html`.
2. Move the rest of the project (`app`, `bootstrap`, `config`, `database`,
   `resources`, `routes`, `storage`, `vendor`, `.env`, `artisan`, etc. — i.e.
   everything that is **not** inside `public/`) somewhere **outside**
   `public_html`, e.g. directly into the account's home directory.
3. In `public_html`, open `index.php` and find these two lines near the top:
   ```php
   require __DIR__.'/../vendor/autoload.php';
   $app = require_once __DIR__.'/../bootstrap/app.php';
   ```
   Change the `../` on both to point at wherever you put the project in
   step 2 above, e.g. if the project now lives directly in your home
   directory:
   ```php
   require __DIR__.'/../sms-temp/vendor/autoload.php';
   $app = require_once __DIR__.'/../sms-temp/bootstrap/app.php';
   ```

Method A is strongly preferred if it's available to you — it's simpler and
harder to get wrong.

---

## Step 7 — Install the application's dependencies (Composer)

This project needs its PHP libraries installed via Composer before it can
run — the `vendor/` folder is not included in the zip.

**[Terminal]**
```
cd ~/sms-temp
composer install --no-dev --optimize-autoloader
```

**[No Terminal]**
Most shared hosts don't offer Composer without a terminal. Your options:
1. Ask your host's support to run the command above for you — many hosts
   will do this on request.
2. Run `composer install` on your own computer (inside the project folder)
   first, then upload the resulting `vendor/` folder along with everything
   else in Step 5. This works but makes the upload much bigger and slower.
3. Check if your host's cPanel has a **"Setup Node.js/PHP App"** or
   **"Git Version Control"** tool — these sometimes include a "Run Composer"
   button without needing a real terminal.

---

## Step 8 — Create and configure the `.env` file

This file holds all the settings specific to your server (database
password, mail settings, etc) and must **never** be uploaded to a public
repository.

1. In File Manager, go to the project's top-level folder (not `public/`).
2. Find the file named `.env.production.example` — I prepared this
   specifically for a cPanel deployment like this one.
3. Make a copy of it and rename the copy to exactly `.env` (no file
   extension after that).
4. Open `.env` and fill in / check these values:

   | Setting | What to put |
   |---|---|
   | `APP_URL` | Your real domain, with `https://` (even before you set up SSL — see Step 15) |
   | `DB_DATABASE` | The full database name from Step 2, e.g. `yourcpanelusername_smsdb` |
   | `DB_USERNAME` | The full username from Step 3, e.g. `yourcpanelusername_smsuser` |
   | `DB_PASSWORD` | The password you set in Step 3 |
   | `MAIL_HOST`, `MAIL_USERNAME`, `MAIL_PASSWORD` | See Step 14 |
   | `ADMIN_EMAIL`, `ADMIN_USERNAME` | The login you want for the real Super Admin account |
   | `ADMIN_PASSWORD` | Leave this **blank** — a strong one will be generated for you in Step 10 and shown once. Only fill this in if you want to choose it yourself. |

   Leave everything else in the file as it already is — those defaults
   (`APP_DEBUG=false`, file-based sessions/cache, etc) are already set
   correctly for this kind of hosting.

---

## Step 9 — Generate the application key

Every Laravel app needs a unique, random encryption key. Without it, logins
and encrypted data won't work.

**[Terminal]**
```
cd ~/sms-temp
php artisan key:generate
```

**[No Terminal]**
1. On your own computer (with PHP installed) or using an online
   "Laravel APP_KEY generator" tool, generate a key — it looks like
   `base64:` followed by random characters.
2. Open `.env` in File Manager and paste it as the value of `APP_KEY=`.

---

## Step 10 — Import the database (run the migrations)

This creates every table the application needs and sets up the real Super
Admin account.

**[Terminal]**
```
cd ~/sms-temp
php artisan migrate --force
php artisan db:seed --force
```
Watch the output of the `db:seed` command — it will print your Super Admin
username and a generated password. **Copy this down immediately; it is
shown only once.**

**[No Terminal]**
If your host has **phpMyAdmin** but no terminal, running Laravel migrations
without a terminal is genuinely difficult, because migrations are PHP code,
not plain SQL. Your realistic options, in order of preference:
1. Ask your host's support to run the two commands above for you.
2. Check for a **"Cron Jobs"** feature (Step 13) — you can create a
   **one-time** cron job that runs the command once, then delete the cron
   job immediately after it has run. This works on almost every host, even
   without a terminal.
3. As a last resort, some "Setup PHP App" tools in cPanel include a command
   box for exactly this purpose — look for it before resorting to option 2.

> **Do not run `php artisan db:seed` a second time on a real database.**
> The seeder wipes and replaces the `settings` table, which would erase
> any branding/settings you've already configured. If you need to add a
> setting later, use the Settings page in the app itself, not the seeder.

---

## Step 11 — Set up file storage

The app stores uploaded photos, logos, and favicons in `storage/app/public`,
but serves them from `public/storage` — these need to be linked together.

**[Terminal]**
```
cd ~/sms-temp
php artisan storage:link
```

**[No Terminal]**
cPanel's File Manager cannot create this kind of link directly. Two options:
1. Use the same one-time cron job trick as Step 10, with the command
   `php artisan storage:link`.
2. If neither works, create a plain PHP file called `linkstorage.php` in
   your project's top-level folder containing:
   ```php
   <?php
   symlink(__DIR__.'/storage/app/public', __DIR__.'/public/storage');
   echo 'Done. Delete this file now.';
   ```
   Visit it once in your browser (adjusted to wherever it ends up being
   reachable), confirm it says "Done", then **delete the file immediately**
   — leaving it on the server is a security risk.

---

## Step 12 — File permissions

Two folders need to be writable by the web server, or you'll see "Internal
Server Error" / blank pages:

- `storage/` (and everything inside it)
- `bootstrap/cache/`

**[Terminal]**
```
cd ~/sms-temp
chmod -R 775 storage bootstrap/cache
```

**[No Terminal]**
1. In File Manager, right-click the `storage` folder → **Permissions**.
2. Set it to **775** (or **755** if your host doesn't allow group-write —
   try 775 first; if the app still can't write, try 755, then ask your host
   which their server expects).
3. Tick **"Recurse into subdirectories"** if offered, so every folder and
   file inside `storage` gets the same permission.
4. Repeat for `bootstrap/cache`.

---

## Step 13 — Cron job (optional, for future use)

As of this version, the app has no scheduled background tasks, so this step
is **not required** for the app to work today. It's good practice to set up
anyway, so it's ready if a future update adds one (e.g. automatic overdue-fee
reminders).

1. In cPanel, open **"Cron Jobs"**.
2. Add a new cron job that runs **every minute** (`* * * * *`) with the
   command:
   ```
   cd /home/yourcpanelusername/sms-temp && php artisan schedule:run >> /dev/null 2>&1
   ```
   (adjust the path to match where your project actually lives)

---

## Step 14 — Email (SMTP) setup

The app sends email for password resets and (depending on what's configured)
other notifications. Without this, "Forgot Password" will silently fail.

**Easiest option — use a mailbox on your own hosting:**
1. In cPanel, open **"Email Accounts"** and create one, e.g.
   `noreply@yourschooldomain.com`, with a strong password.
2. In your `.env` file, set:
   ```
   MAIL_HOST=mail.yourschooldomain.com
   MAIL_USERNAME=noreply@yourschooldomain.com
   MAIL_PASSWORD=<the password you just set>
   MAIL_PORT=587
   MAIL_ENCRYPTION=tls
   MAIL_FROM_ADDRESS=noreply@yourschooldomain.com
   ```
   (Your host's "Email Accounts" page usually shows the exact
   `MAIL_HOST`/port to use under "Connect Devices" or "Set Up Mail Client" —
   use those exact values if they differ from the above.)

**Alternative:** use a third-party sender (Gmail, SendGrid, Mailgun, etc) —
the same five settings apply, just with that provider's host/port/username/
password instead.

---

## Step 15 — SSL (HTTPS)

Running the school's real data over plain `http://` is not safe — logins,
fees, and personal information would travel unencrypted.

1. In cPanel, open **"SSL/TLS Status"** (or look for **"AutoSSL"**).
2. Select your domain and run **"Run AutoSSL"**. Most hosts issue a free
   certificate (via Let's Encrypt) automatically within a few minutes, at
   no cost.
3. Once it's active (you can visit `https://yourdomain.com` and see a padlock),
   go back into your `.env` file and:
   - Make sure `APP_URL=https://yourdomain.com` (with the `s`)
   - Make sure `SESSION_SECURE_COOKIE=true`
4. Most hosts also offer a **"Force HTTPS Redirect"** toggle on the same
   SSL/TLS page — turn it on so `http://` visitors are sent to `https://`
   automatically.

---

## Step 16 — Test everything

Work through this list in order. If something fails, check the
Troubleshooting section below before moving on.

1. Visit your domain — you should land on the login page, styled correctly
   (not a blank white page or raw error text).
2. Log in with the Super Admin credentials from Step 10.
3. **Settings** → confirm the page loads, change the School Name, save, and
   confirm it actually saved after a page refresh.
4. **Settings → Branding** → upload a logo and a favicon; confirm the
   favicon appears in the browser tab.
5. **Users** → create a Teacher account.
6. **Classes / Sections / Subjects** → create one of each.
7. **Students** → add a student, assigning the class/section you just made.
   Confirm a temporary password is shown in a popup — write it down and
   confirm you can log out and log back in as that student.
8. **Attendance** → take attendance for the class you created.
9. **Marks** → enter a score for the student, including leaving one field
   blank, and confirm it saves without an error.
10. **Fees & Payments** → create a fee, record a payment against the
    student, and download the PDF receipt — confirm it opens correctly
    (this is the one area I could not test in my own environment — see
    "Known open items" below).
11. **Library** (if enabled) → add a book, log in as the student, and
    request to borrow it.
12. **Announcements** → post one, and confirm it shows on the dashboard for
    the right role.
13. Log out, click **"Forgot password"**, and confirm the reset email
    actually arrives.
14. Open the site on your phone, or shrink your browser window — confirm
    wide tables (like the marks entry grid) scroll sideways instead of
    breaking the page.

---

## Troubleshooting

**Blank white page, nothing else**
Almost always means `APP_DEBUG=false` and an error is happening silently.
Temporarily set `APP_DEBUG=true` in `.env`, reload the page to see the real
error, fix it, then **set `APP_DEBUG=false` again before telling anyone the
site is live** — leaving debug mode on in production exposes your server's
internal details to anyone who visits.

**"No application encryption key has been specified"**
You skipped or mistyped Step 9. Re-check that `APP_KEY=` in `.env` has a
real value starting with `base64:`.

**"SQLSTATE[HY000] [1045] Access denied for user..."**
Your `DB_DATABASE` / `DB_USERNAME` / `DB_PASSWORD` in `.env` don't match
what you actually created in Steps 2–4. Double-check the **full** names
including the `yourcpanelusername_` prefix.

**"The stream or file ... could not be opened: failed to open stream:
Permission denied"**
Revisit Step 12 — `storage/` or `bootstrap/cache/` isn't writable.

**Images/logo/favicon don't show (broken image icon)**
Revisit Step 11 — the storage link wasn't created correctly.

**"500 Internal Server Error" immediately, before even a blank page**
Usually a PHP version mismatch, or `vendor/` wasn't uploaded/installed
correctly. Re-check Steps 1 and 7.

**Password reset emails never arrive**
Re-check Step 14. Also check the email account's own "Sent" folder in
cPanel's webmail — if it shows as sent, the problem is on the receiving end
(spam folder, wrong address); if it's not even in "Sent", the `.env` MAIL_*
values are wrong.

**PDF receipts/report cards look broken, show missing text, or the download
fails**
This project uses a PDF library (`dompdf`) that I flagged back in Phase 2 as
not independently verified against PHP 8.x in my own environment, because I
could not install Composer packages there. If this happens, tell me the
exact error and I can update the library version and retest the affected
code with you.

---

## Appendix — things worth keeping for reference

**Demo/test accounts** (only exist if you ran the demo seeder on a non-production
environment — see the warning in Step 10):

| Role | Username | Password |
|---|---|---|
| Admin | `admin` | `123456` |
| Teacher | `teacher` | `123456` |
| Parent | `parent` | `123456` |
| Accountant | `accountant` | `123456` |
| Librarian | `librarian` | `123456` |
| Student | `student` | `123456` |

**These must never exist on a real production database.** The seeder that
creates them is already blocked from running when `APP_ENV=production`, but
if you ever copy a test database onto the live server, delete these accounts
first.

**Full change history:** see `CHANGELOG.md` in the project's top-level
folder for a complete, phase-by-phase record of every change made to this
project, including the full list of database migrations and the order they
need to run in (`php artisan migrate` handles the order automatically —
this is just for your reference).

**Where things live:**
- Application settings (school name, logo, colours, fees, etc.): **Settings**
  page in the app, not in any file
- Server settings (database password, mail, etc.): `.env` file, project
  top-level folder
- Uploaded files (photos, logos): `storage/app/public/`, served via the
  `public/storage` link from Step 11
