# Deployment — cPanel

Two subdomains:

| Part      | Subdomain                          | Document root                                   |
|-----------|------------------------------------|-------------------------------------------------|
| Backend   | `api-udyogo.demosystem.in`         | `…/udyogo_sales_backend/public`                 |
| Frontend  | `udyogo-sales.demosystem.in`       | `…/udyogo-sales.demosystem.in` (its own folder) |

The API uses **Bearer-token auth** (Laravel Sanctum personal access tokens), so no
shared cookies/CSRF between the domains — only CORS needs to allow the frontend.

---

## 1. Backend (Laravel) → `api-udyogo.demosystem.in`

### A. Create the subdomain
cPanel → **Domains / Subdomains** → add `api-udyogo` and set its **Document Root** to
`…/udyogo_sales_backend/public`.
*(If your host won't let you point the docroot into `/public`, upload the project so its
root is the docroot — the included root `.htaccess` forwards requests into `/public`.)*

### B. Upload the code
Upload the **`udyogo_sales_backend`** folder (zip → extract). Do **not** upload `.env`,
`vendor/`, `node_modules`, or `storage/*.log`.

### C. Database
cPanel → **MySQL Databases**: create a DB + user, grant all privileges.

### D. `.env`
Copy `.env.production.example` → `.env` and fill in:
- `APP_KEY` — run `php artisan key:generate` (or paste a `base64:` key).
- `APP_URL=https://api-udyogo.demosystem.in`
- `CORS_ALLOWED_ORIGINS=https://udyogo-sales.demosystem.in`
- `DB_*` — the database you just created.

### E. Install & build (via cPanel Terminal, or run locally and upload `vendor/`)
```bash
composer install --no-dev --optimize-autoloader
php artisan key:generate          # if APP_KEY is blank
php artisan migrate --force
php artisan db:seed --force       # optional: seeds the 3 logins + dummy data
php artisan storage:link          # makes uploaded avatars publicly reachable
php artisan config:cache
php artisan route:cache
```
> No SSH/Terminal? Run `composer install --no-dev` locally and upload the resulting
> `vendor/` folder, then run the artisan commands via a one-off script or cPanel's
> "Setup PHP App" terminal.

### F. Permissions
`storage/` and `bootstrap/cache/` must be writable (755/775). If avatar uploads fail,
`chmod -R 775 storage bootstrap/cache`.

### G. Verify
`https://api-udyogo.demosystem.in/up` should return a health page, and
`POST https://api-udyogo.demosystem.in/api/auth/login` should authenticate.

---

## 2. Frontend (React/Vite) → `udyogo-sales.demosystem.in`

### A. Build locally
`.env.production` is already set to `VITE_API_URL=https://api-udyogo.demosystem.in/api`.
```bash
cd udyogo_sales_frontend
npm ci
npm run build           # outputs dist/
```

### B. Upload
Create the subdomain `udyogo-sales` in cPanel, then upload the **contents of `dist/`**
(not the `dist` folder itself) into its document root. The SPA `.htaccess` is bundled
in `dist/` automatically (it forces HTTPS, routes all paths to `index.html`, and sets
cache headers).

### C. Verify
Open `https://udyogo-sales.demosystem.in`, log in with a seeded account
(`admin@udyogo.com` / `admin@udyogo`). Check the browser Network tab — calls should hit
`https://api-udyogo.demosystem.in/api/...` with `200`s.

---

## Re-deploying
- **Frontend:** `npm run build` → re-upload `dist/` contents.
- **Backend:** upload changed files → `php artisan migrate --force && php artisan config:cache`.
  After any `.env` or route change, re-run `config:cache` / `route:cache`.

## Troubleshooting
- **CORS error** → `CORS_ALLOWED_ORIGINS` must exactly match the frontend origin
  (scheme + host, no trailing slash); run `php artisan config:clear` after editing.
- **419 / auth bounces to /login** → stale token in the browser; log out/in.
- **500 on API** → check `storage/logs/laravel.log`; usually missing `APP_KEY`,
  DB creds, or unwritable `storage/`.
- **Avatars 404** → `php artisan storage:link` wasn't run (or symlinks disabled —
  then copy `storage/app/public` to `public/storage`).
- **Blank SPA / 404 on refresh** → the `.htaccess` didn't upload, or `mod_rewrite`
  is off for the subdomain.
