# Deploying Niyarasa

This is a production deployment guide for the Niyarasa Laravel 12 store. It
assumes a Linux VPS (Ubuntu 22.04+) running Nginx + PHP-FPM + MySQL — the
most common target for a Laravel app. An Apache alternative is included
where it differs.

## 1. Server requirements

- PHP 8.2+ with extensions: `mbstring`, `xml`, `curl`, `zip`, `gd` or
  `imagick`, `pdo_mysql`, `bcmath`, `intl`, `fileinfo`
- MySQL 8+ or MariaDB 10.6+
- Composer 2.x
- Node.js 20+ and npm (build step only — not needed at runtime)
- Nginx (or Apache with `mod_rewrite` + `mod_ssl`)
- Supervisor (runs the queue worker)
- Certbot (free TLS via Let's Encrypt)

## 2. First-time server setup

```bash
# Clone the repo somewhere outside the web root's public reach, e.g.
sudo mkdir -p /var/www/niyarasa
sudo chown $USER:$USER /var/www/niyarasa
git clone <your-repo-url> /var/www/niyarasa
cd /var/www/niyarasa

# Environment
cp .env.production.example .env
php artisan key:generate
# Now edit .env: DB credentials, APP_URL, mail SMTP, TRUSTED_PROXIES if
# behind a load balancer, and the Niyarasa brand/payment settings.

# Dependencies + build
composer install --no-dev --optimize-autoloader
npm ci && npm run build

# Database
php artisan migrate --force
php artisan db:seed --force   # only on a genuinely empty database — see §6

# Storage
php artisan storage:link

# Framework caches (safe no-ops if nothing changed)
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

# Permissions — the web server user needs write access to these two only
sudo chown -R www-data:www-data storage bootstrap/cache
sudo chmod -R 775 storage bootstrap/cache
```

Then wire up the web server (§3), the queue worker (§4), and TLS (§5)
before pointing DNS at the box.

## 3. Web server

- **Nginx** (recommended): `deploy/nginx.conf.example` — copy to
  `/etc/nginx/sites-available/niyarasa`, symlink into `sites-enabled`,
  adjust the domain and paths, `nginx -t && systemctl reload nginx`.
- **Apache**: `deploy/apache-vhost.conf.example`. `public/.htaccess`
  already ships with the repo and handles the front-controller rewrite —
  just make sure `AllowOverride All` is set and `mod_rewrite` is enabled.

Either way, the document root is `public/`, never the project root — the
`.env` file, `app/`, and everything else must not be web-accessible.

## 4. Queue worker

`QUEUE_CONNECTION=database` means queued jobs — currently the contact-form
email (`ContactMessageMail implements ShouldQueue`, Step 7) — sit in the
`jobs` table until a worker processes them. Nothing sends until one runs.

```bash
sudo cp deploy/supervisor-queue-worker.conf.example /etc/supervisor/conf.d/niyarasa-worker.conf
# edit the path inside if it's not /var/www/niyarasa
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start niyarasa-worker:*
```

Also add the Laravel scheduler to cron (harmless even with no scheduled
tasks defined yet — cheap to have in place for when one is added):

```bash
crontab -e
# add:
* * * * * cd /var/www/niyarasa && php artisan schedule:run >> /dev/null 2>&1
```

## 5. HTTPS

```bash
sudo certbot --nginx -d niyarasa.com -d www.niyarasa.com
```

Certbot auto-renews via its own systemd timer/cron entry — no extra setup.
Once live, confirm in `.env`:

```
APP_URL=https://niyarasa.com
SESSION_SECURE_COOKIE=true
```

`AppServiceProvider` already forces `https://` on every generated URL when
`APP_ENV=production` (Step 16), so this isn't optional to skip.

## 6. Before going live — checklist

- [ ] `.env`: `APP_ENV=production`, `APP_DEBUG=false` — debug mode on a
      live store leaks stack traces (file paths, query bindings, env
      values) to anyone who triggers an error.
- [ ] `php artisan db:seed --force` — with `APP_ENV=production`,
      `DatabaseSeeder` automatically skips the local convenience
      credentials (`admin@niyarasa.com` / `password`) and the sample
      customer account entirely. Instead it generates a random 16-character
      password, creates the one admin account, and prints the password to
      the console **once** — it is not stored anywhere or shown again, so
      copy it immediately and change it after first login.
- [ ] Real SMTP credentials in `.env` (`MAIL_MAILER=smtp` + host/port/
      user/pass) — `log` driver silently writes emails to a log file
      instead of sending them.
- [ ] EasyPaisa account number/name and the COD restricted city are set
      correctly — either in `.env` or (preferably) via the admin Settings
      page, which takes precedence and doesn't need a redeploy to change.
- [ ] Facebook/WhatsApp links set in Settings if you want them live in the
      header/footer (Step 1 — blank hides the icon, doesn't break it).
- [ ] `php artisan storage:link` has run — without it, every product
      image, banner, and payment-proof screenshot 404s.
- [ ] A real domain in `APP_URL`, matching what's in the Nginx/Apache
      config and the Certbot cert.
- [ ] `SESSION_SECURE_COOKIE=true` only after TLS is actually working —
      setting it before HTTPS is live locks everyone out (browsers refuse
      to send secure cookies over plain HTTP).

## 7. Deploying an update

```bash
cd /var/www/niyarasa
git pull
bash deploy/deploy.sh
```

`deploy/deploy.sh` wraps the whole cycle: maintenance mode → composer
install → npm build → migrate → re-link storage → rebuild all caches →
restart queue workers → bring the site back up. It's idempotent — safe to
run even when a step has nothing to do.

**If you ever run the test suite on this server** (CI, staging, or a
manual check), build assets first: `npm run build` before `php artisan
test`. Every view that uses `@vite()` throws if `public/build/manifest.json`
doesn't exist — a real issue hit and fixed in Step 15, worth remembering
here since it's exactly the kind of thing that looks like a hang.

## 8. Backups

At minimum, a nightly `mysqldump` of the database plus the `storage/app/public`
directory (product images, banners, payment proof screenshots — none of
this is reproducible from code). A simple cron entry:

```bash
0 3 * * * mysqldump -u <user> -p<pass> niyarasa_production | gzip > /var/backups/niyarasa-$(date +\%F).sql.gz
```

Rotate old backups and store at least one copy off-server (S3, another
host) — a backup that lives only on the machine it's backing up doesn't
survive that machine failing.

## 9. Monitoring

- `storage/logs/laravel.log` is the first place to look after any
  incident — `LOG_STACK=daily` (set in `.env.production.example`) keeps
  it from growing forever.
- Consider an error-tracking service (Sentry, Bugsnag, Flare) for
  real-time exception alerts instead of only finding out when a customer
  reports a problem.
- The `/up` health-check route (Laravel's default, still wired in
  `bootstrap/app.php`) is a good target for uptime monitoring (UptimeRobot,
  a load balancer health check, etc.).

## 10. What's already handled in code

- Security headers (`X-Frame-Options`, `X-Content-Type-Options`,
  `Referrer-Policy`, `Permissions-Policy`) on every response —
  `App\Http\Middleware\SecurityHeaders`, registered globally.
- Forced HTTPS on generated URLs in production — `AppServiceProvider`.
- Trusted proxy support for load-balanced/reverse-proxied deployments —
  `TRUSTED_PROXIES` in `.env`, empty (safe) by default.
- Rate limiting on the public forms most likely to be abused: contact
  (5/min), newsletter signup (5/min), reviews (10/min), checkout (10/min)
  — on top of the dedicated login throttle from Step 5.
- CSRF protection, password hashing, and mass-assignment protection are
  Laravel defaults already in effect throughout.
