# Deploying the Technifying DMS to a live server

This archive holds the dealership system's own code, the deployment scripts, and notes. It does **not** hold Laravel itself or third-party libraries (`vendor/`): `deploy/install.sh` downloads the official Laravel 12 framework and the libraries on your server and puts the system on top. The server therefore needs internet access during install and upgrades.

## 1. What the server needs
- Ubuntu 22.04/24.04 (or similar), 2 CPU / 2 GB RAM or more, 10 GB disk plus room for photos
- PHP 8.2 or newer with: bcmath, gd, mbstring, openssl, pdo_mysql, curl, fileinfo, zip, xml (and exif, recommended)
- MySQL 8 or MariaDB 10.6+, Composer 2, Node.js 20+ with npm, rsync, nginx (or Apache), supervisor, cron
- A domain name with HTTPS (Let's Encrypt is fine). **M-Pesa and eTIMS will not work without a public HTTPS address.**
- Shared hosting works only if it gives you SSH, PHP 8.2+, Composer and cron. Without a way to run a background worker, use cron instead (see step 7).

Ubuntu example:
```bash
sudo apt install nginx mysql-server supervisor rsync unzip git curl \
  php8.2-fpm php8.2-cli php8.2-mysql php8.2-bcmath php8.2-gd php8.2-mbstring php8.2-curl php8.2-xml php8.2-zip php8.2-intl php8.2-exif
# Composer: https://getcomposer.org/download/   Node 20: https://nodejs.org/
```

## 2. Database
```sql
CREATE DATABASE dms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'dms'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON dms.* TO 'dms'@'localhost';
```

## 3. Install
```bash
unzip technifying-dms-v1.0.0.zip -d /tmp/dms-release
sudo mkdir -p /var/www/dms && sudo chown $USER /var/www/dms
bash /tmp/dms-release/technifying-dms/deploy/install.sh /var/www/dms
```
Then edit `/var/www/dms/.env` (database, `APP_URL`, `DMS_ADMIN_EMAIL`, `DMS_ADMIN_PASSWORD`, `SITE_*`), and:
```bash
cd /var/www/dms
php artisan migrate --force --seed
sudo chown -R www-data:www-data storage bootstrap/cache
```
**Back up `APP_KEY` from `.env` now** (password manager, not email). It encrypts customers' ID numbers, KRA PINs and the eTIMS key; lose it and that data is unreadable, backups included.

## 4. Web server
Copy `deploy/nginx.conf` to `/etc/nginx/sites-available/dms`, change the domain and paths, enable it, then `sudo certbot --nginx -d your.domain`. `sudo nginx -t && sudo systemctl reload nginx`.

## 5. Scheduler (cron)
`sudo crontab -u www-data -e` and add the lines in `deploy/crontab.txt`. The scheduler sends eTIMS retries, chases M-Pesa callbacks that never arrived, expires reservations, and writes the heartbeat that `/health` watches.

## 6. Background worker
```bash
sudo cp deploy/supervisor-dms-worker.conf /etc/supervisor/conf.d/dms-worker.conf
sudo supervisorctl reread && sudo supervisorctl update && sudo supervisorctl start dms-worker:*
```
Callbacks from Safaricom, payment matching, eTIMS sending and wishlist alerts run here.

## 7. No supervisor? (shared hosting)
Set `QUEUE_CONNECTION=database` and add a cron line: `* * * * * cd /var/www/dms && php artisan queue:work --stop-when-empty --max-time=55 >> /dev/null 2>&1`. Jobs then run within a minute.

## 8. Optimise and check
```bash
php artisan config:cache && php artisan route:cache && php artisan view:cache && php artisan event:cache
php artisan dms:preflight          # every line should be PASS, or a WARN you understand
```
Open `https://your.domain/login` and sign in with the admin from `.env` (you must change the password). Then:
1. **Branches**: rename the sample branches HQ, NBO and MSA and add your real ones, with KRA PIN and contact details.
2. **Users**: add staff with the right roles and branches. Salespeople need role *Sales Executive* to receive leads.
3. **Settings**: CRM settings (business hours, lead rules, response targets), discount limits (`sales.*` settings).
4. Add a test vehicle, photos, and list it: `https://your.domain/cars`.

## 9. Go-live checklist
**M-Pesa**: Daraja app approved, production credentials in `.env`, `MPESA_ENV=production`, `php artisan mpesa:register-urls`, one real KSh 10 payment end to end (STK Push, then a paybill payment with a deal number as the account).
**KRA eTIMS**: OSCU registered and **approved by KRA**, device initialised under *eTIMS > Devices* in sandbox first, item class codes set, test invoices accepted; then switch to production, initialise again, set `ETIMS_ENFORCE=true`.
**Legal**: lawyer has approved the sales agreement, test-drive indemnity and reservation terms (`config/deals.php`, `config/crm.php`, `config/experience.php`).
**Data Protection Act**: register with the Office of the Data Protection Commissioner if you have not; the privacy notice on your website should describe what you collect (the enquiry and reservation forms collect names, phone numbers and emails).
**Tax**: your accountant has confirmed VAT treatment of the vehicles you sell.
**Final check**: `php artisan dms:preflight --live` shows no FAIL.

## 10. Running it
- **Backups**: `deploy/backup.sh` (cron does it nightly). Copy the files off the server. Practise a restore on a spare machine before you need one.
- **Monitoring**: point an uptime monitor at `https://your.domain/health` (add the `X-Health-Token` header for details). It reports *degraded* if the scheduler or worker stops.
- **Logs**: `storage/logs/` (daily files). Failed background jobs: `php artisan queue:failed`.
- **Upgrades**: unzip the new archive and run `bash deploy/update.sh /var/www/dms` (backs up, takes the site offline briefly, migrates, rebuilds).
- **Phone app**: staff open `https://your.domain/m` on their phone and use "Add to Home screen". Raise `PWA_VERSION` in `.env` to make every phone refresh the app after a change.
- **Server hardening**: firewall allowing only 22, 80, 443 (`ufw`); SSH keys only; automatic security updates; `APP_DEBUG=false` always.

## 11. Troubleshooting
| Symptom | Likely cause |
|---|---|
| Blank page or 500 | `storage/` not writable by www-data, or `.env` wrong. Read `storage/logs/laravel-*.log` |
| M-Pesa prompt arrives but nothing posts | Worker not running, or callback URL unreachable. Check `/health`, `queue:failed`, the **M-Pesa** page |
| eTIMS invoice stays "waiting" | Worker or cron not running; device not initialised (*eTIMS > Devices*) |
| Photos fail to upload | `client_max_body_size` in nginx, PHP `upload_max_filesize` and `post_max_size` (set to 25M) |
| Styles missing | `npm run build` did not finish, or `public/build` not readable |
| Customers cannot sign in to the portal | They need an invitation link from the customer page, then use their phone number and the password they chose |
