# Deploying VibePass Tickets to Truehost cPanel (WebHosting Pro)

This folder is a self-contained, production-built copy of the ticketing app,
built with Next.js `output: "standalone"`. It bundles its own trimmed
`node_modules` and does **not** need `npm install` on the server. It's a
Node.js app, not a static site — everything (checkout, M-Pesa/Stripe/PayPal
webhooks, admin/dashboard, cron) needs the Node process running, so it must
be deployed via cPanel's **Setup Node.js App** (Passenger), not File Manager
alone under `public_html`.

The database (Supabase) and payment processors are unaffected by this move —
they're external services this app talks to over HTTPS, so nothing needs to
be migrated. This is purely about hosting the Node.js process itself.

## 1. Create the Node.js App in cPanel

1. cPanel → **Setup Node.js App** → **Create Application**.
2. **Node.js version**: pick the highest available (this app needs Node 18.18+;
   prefer 20 or 22 if Truehost offers it).
3. **Application mode**: Production.
4. **Application root**: a folder outside `public_html`, e.g. `ticketing-app`
   (cPanel creates it under your home directory). Don't put it directly in
   `public_html` — Passenger manages routing to it via the Application URL.
5. **Application URL**: the domain or subdomain this should serve
   (e.g. `tickets.yourdomain.com`, or the root domain if this replaces what's
   there).
6. **Application startup file**: `server.js`
7. Click **Create**.

## 2. Upload the files

1. Open **File Manager**, navigate to the application root you picked above.
2. Upload `ticketing-app-cpanel.zip` there and extract it in place (right-click
   → Extract), so `server.js` sits directly in the application root.
3. Do **not** click "Run NPM Install" in the Node.js App UI — dependencies are
   already bundled in `node_modules`. Running it is harmless but unnecessary
   and will be slow on shared hosting.

## 3. Set environment variables

In the Node.js App's **Environment Variables** section, add these (values
from your local `.env.local` — never commit or share that file):

| Variable | Value |
|---|---|
| `NEXT_PUBLIC_SUPABASE_URL` | same as `.env.local` |
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | same as `.env.local` |
| `SUPABASE_SERVICE_ROLE_KEY` | same as `.env.local` |
| `APP_SECRETS_KEY` | **same as `.env.local`, exactly** — this decrypts the Stripe/M-Pesa/PayPal/Africa's Talking keys stored in the `app_secrets` Supabase table. If this doesn't match, none of those integrations will work even though nothing else changed. |
| `TICKET_SIGNING_SECRET` | same as `.env.local` — changing this invalidates the QR codes on every ticket already issued, so copy the existing value, don't generate a new one |
| `NEXT_PUBLIC_SITE_URL` | the real URL this app will be reachable at, e.g. `https://tickets.yourdomain.com` |
| `CRON_SECRET` | a new random secret (e.g. `openssl rand -hex 32`) — see step 5 |

You do **not** need to re-enter Stripe/M-Pesa/PayPal/Africa's Talking keys —
those are stored encrypted in Supabase and managed from **/admin/settings/secrets**
in the app itself, decrypted at runtime using `APP_SECRETS_KEY` above.

After adding variables, click **Restart** on the Node.js App.

## 4. Start the app

Back in **Setup Node.js App**, hit **Restart** (or **Start** if it isn't
running). Then visit your Application URL — you should see the VibePass
homepage. If it doesn't load, check the app's log file (linked from the
Node.js App page) for the actual error — most first-run failures are a
missing/mistyped environment variable.

## 5. Replace the Vercel cron with a cPanel cron job

`vercel.json`'s daily cron (`/api/cron/campaign-sender`) doesn't exist on
cPanel — that config only means anything to Vercel. Recreate it as a real
cron job:

cPanel → **Cron Jobs** → Add New Cron Job:

- **Schedule**: every 5 minutes (`*/5 * * * *`) — the route processes one
  bounded batch per call and is designed to be polled frequently; the daily
  schedule in `vercel.json` was only because 5-minute crons need a paid
  Vercel plan, a limitation that doesn't apply here.
- **Command**:
  ```
  curl -s -H "Authorization: Bearer YOUR_CRON_SECRET" https://tickets.yourdomain.com/api/cron/campaign-sender > /dev/null 2>&1
  ```
  Replace `YOUR_CRON_SECRET` with the value you set in step 3, and the URL
  with your real Application URL.

## 6. DNS / domain

Point the domain or subdomain you chose in step 1 at this Truehost hosting
account (A record to the server IP, or leave as-is if the domain already
lives on this cPanel account). If you're keeping the existing Vercel
deployment live at the same domain, use a **different subdomain** here
(e.g. `tickets-ke.yourdomain.com`) until you're ready to cut over, then
repoint DNS when this copy is verified working.

## Known constraints on shared hosting

- **Memory/CPU**: shared cPanel plans cap Node process resources. This app
  is lightweight (no heavy server-side rendering loops), so it should be
  fine for moderate traffic, but watch the app logs for OOM kills under load.
- **Image optimization**: `next/image` works without extra setup, but
  self-hosted optimization is slower without the optional `sharp` package
  (not currently a dependency). If Truehost's Node.js Selector lets you add
  it and your plan's Node version has a prebuilt binary for it, it's worth
  adding; otherwise images still work, just less optimized.
- **Rebuilding**: this is a snapshot, not a live pipeline. To ship new
  changes, rebuild locally (`next build` in `ticketing-app/`) and re-upload
  this standalone bundle — there's no auto-deploy from git here the way
  there is on Vercel.
