# Deployment — cPanel (Node + Postgres)

The owner confirmed their cPanel host supports **Node.js apps (Passenger)** and
**PostgreSQL**. This page is the concrete deploy plan for that environment, plus the
**checks to run before building** (some cPanel hosts are more capable than others).

> ⚠️ The cPanel + Passenger path is the **highest-risk part of the whole plan**. Validate
> §1 first — if any check fails, the fallback options in §6 keep the project moving.

## 1. Pre-build host checklist (do this first)

Run these with the host / in the cPanel terminal **before** writing platform code:

| Check | Why it matters | How to verify |
|---|---|---|
| **Node ≥ 20** available | Medusa v2 requires Node 20+ | cPanel "Setup Node.js App" version list, or `node -v` in Terminal |
| **PostgreSQL** offered | Medusa's primary DB (MySQL is **not** supported) | cPanel → PostgreSQL Databases |
| **Long-running Passenger apps** allowed | Medusa is a persistent server, not per-request PHP | Confirm the host doesn't kill idle/long processes; check process/RAM limits |
| **SSH / Terminal** access | Needed for `npm install`, builds, `medusa db:migrate` | cPanel → Terminal or SSH access |
| **RAM** ≥ ~1–2 GB usable | Building Next.js/admin + running 2 Node apps | Host plan specs |
| **Outbound HTTPS** allowed | Calls to Claude/Gemini/Razorpay/Stripe | Usually yes; confirm no egress firewall |
| **Redis (Upstash) from day 1** | cPanel/Passenger sleeps apps → in-memory event/queue state is unsafe; use durable Redis | Create a free **Upstash** serverless Redis (TLS `rediss://`); no host install needed (see §4 + `07 §14`) |
| **Keep-alive cron** | Stop Passenger idling the apps (cold starts) | cPanel → Cron Jobs: curl backend + storefront every ~5 min |
| **Cron** | Schedule marketing-agent runs (or use n8n) | cPanel → Cron Jobs |

If **Node 20+ and PostgreSQL with persistent Passenger** are all present, the plan proceeds
as written. If not, see §6.

## 2. Topology on the host

Two Passenger Node apps + one Postgres DB (see `01-architecture.md §5`):

| App | Port (internal) | Public mapping |
|---|---|---|
| Medusa backend (`:9000`) | 9000 | `admin.jaipurhandloomia.com` (admin UI) + Store/Admin APIs |
| Next.js storefront (`:8000`) | 8000 | `jaipurhandloomia.com` / `www` |
| PostgreSQL | — | local only |

Each is registered in cPanel **"Setup Node.js App"** with its app root, startup file, and
Node version. Passenger keeps them alive and reverse-proxies the domain to the app.

## 3. Step-by-step (once §1 passes)

1. **Create the Postgres database & user** in cPanel; note host/port/name/user/password.
2. **Upload/clone** the backend and storefront builds into two app directories
   (e.g. `~/apps/medusa` and `~/apps/storefront`).
3. **Backend env** (`~/apps/medusa/.env`):
   ```env
   DATABASE_URL=postgres://USER:PASS@127.0.0.1:5432/DBNAME
   JWT_SECRET=__generate__
   COOKIE_SECRET=__generate__
   STORE_CORS=https://jaipurhandloomia.com
   ADMIN_CORS=https://admin.jaipurhandloomia.com
   ANTHROPIC_API_KEY=__copilot__
   GEMINI_API_KEY=__agents__
   RAZORPAY_KEY_ID=...
   RAZORPAY_KEY_SECRET=...
   STRIPE_API_KEY=...
   # REDIS_URL=...   # optional; omit to use in-memory modules
   ```
4. **Install & migrate** (cPanel Terminal):
   ```bash
   cd ~/apps/medusa && npm ci && npx medusa db:migrate && npm run build
   cd ~/apps/storefront && npm ci && npm run build
   ```
5. **Set the startup file** for each app in "Setup Node.js App" (backend: `medusa start`
   entry; storefront: Next.js production server) and **start** both apps.
6. **Seed**: create the admin user, run the data-migration script to import existing
   marketing runs into `ai_agent_run` (see `03-data-model.md §2a`).
7. **Domains & SSL**: point `jaipurhandloomia.com` → storefront app, `admin.…` → backend;
   issue SSL via cPanel AutoSSL/Let's Encrypt.
8. **Webhooks**: register Razorpay/Stripe webhooks → backend payment endpoints.
9. **Scheduling**: cPanel Cron (or the existing n8n) triggers marketing-agent runs.

## 3a. CI/CD auto-deploy (so you never upload by hand)

The point of the "self-evolving platform" is that **code changes deploy themselves.** A
GitHub Actions workflow watches the release branch and, on every push, deploys to the host
over SSH:

```yaml
# .github/workflows/deploy.yml (sketch)
on:
  push:
    branches: [release]        # the platform's deploy branch
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy over SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.CPANEL_HOST }}
          username: ${{ secrets.CPANEL_USER }}
          key: ${{ secrets.CPANEL_SSH_KEY }}
          script: |
            cd ~/apps/medusa && git pull && npm ci && npx medusa db:migrate && npm run build
            cd ~/apps/storefront && git pull && npm ci && npm run build
            touch ~/apps/medusa/tmp/restart.txt ~/apps/storefront/tmp/restart.txt
```

- **Secrets** (`CPANEL_HOST/USER/SSH_KEY`) live in GitHub Actions secrets, never in the repo.
- **Passenger restart**: touching `tmp/restart.txt` triggers a graceful reload (or use the
  cPanel "Restart" button for the Node app).
- **Rollback** = push the previous commit; deploys are just git state.
- **Migrations** run inside the deploy so the schema stays in sync. To avoid Passenger
  file/db-lock conflicts, the deploy **disables the app, runs `medusa db:migrate`, then
  restarts** (a brief maintenance window), and deploys are **serialized** (no concurrent runs).

This is **Tier 2** of the two change tiers (Tier 1 = live content/theme edits with *no* deploy
at all — see `04-themes-and-plugins.md`). Together they mean **nothing is ever uploaded by
hand** — the exact frustration that started this project.

> **Prereq:** the host must allow **SSH key access** + a git checkout in the app dirs (already
> on the §1 checklist). If SSH deploy isn't available, fall back to a **pull-based deploy**: a
> cron/webhook on the host that runs `git pull && build && restart` on a schedule.

## 4. Redis decision — Upstash from day 1 (decided)

Medusa v2's default Event Bus/Cache/Workflow modules are in-memory. On a normal server that's
fine, but **on cPanel/Passenger the app gets put to sleep and recycled**, which can drop
in-flight events and background jobs (Review 2's durability risk). So the decision is to use
**Upstash serverless Redis (free tier, TLS `rediss://`) from day 1**, set via `REDIS_URL`, to
back the event bus + queues durably **outside** the fragile Passenger process. Paired with the
**keep-alive cron** (§1) this is the hardened all-cPanel path — full table in
`07-architecture-hardening.md §14`.

## 5. Backups & ops

- **DB backups:** cPanel scheduled Postgres dumps (daily) + download off-host weekly.
- **Secrets:** only in app `.env` (outside web root); never in the repo or browser bundles.
- **Updates:** `git pull` build dir → `npm ci && npm run build && medusa db:migrate` →
  restart the Passenger app.
- **Monitoring:** Passenger app status in cPanel; uptime ping on both domains.

## 6. Fallbacks if a §1 check fails

| Failure | Fallback |
|---|---|
| No PostgreSQL (MySQL only) | Use an external managed Postgres (Neon/Supabase free tier) over TLS; keep apps on cPanel |
| Passenger kills long processes / too little RAM | Move the **backend** to a small managed Node host (Railway/Render) or a tiny VPS; keep storefront on cPanel, or move both |
| Node < 20 and not upgradable | Backend on managed Node host; storefront (Next.js) can still build on most hosts |
| No SSH/Terminal | Build artifacts locally/CI, upload the built output; or use a host with shell access |
| No Redis | Use Medusa in-memory defaults (fine for one store) or Upstash |

None of these change the architecture — only *where each Node app runs*. The backend +
storefront + Postgres shape stays identical.
