# Deploying Feater to cPanel

This guide deploys the two apps as **two Node.js applications** under cPanel's
**Setup Node.js App** (Phusion Passenger):

| App | Runs | Suggested domain |
| --- | ---- | ---------------- |
| **API** (`apps/api`, NestJS) | `app.js` → `dist/main.js` | `api.yourdomain.com` |
| **Web** (`apps/web`, Next.js) | `server.js` | `yourdomain.com` |

The database is **cPanel's own PostgreSQL** (created in cPanel → *PostgreSQL
Databases*), running on the same server as the API. Redis is not required.
Uploaded photos are stored on the cPanel disk (persistent), so no S3 is required
to go live.

---

## 0. Prerequisites

- A cPanel host with **Setup Node.js App** (CloudLinux Node.js Selector) and
  **Node 20+** available.
- SSH/**Terminal** access in cPanel (used to build + run migrations). If SSH is
  disabled, ask your host to enable it, or use the app's "Run JS script" panel.
- **PostgreSQL Databases** available in cPanel (see step 1 below to create one).
- Two (sub)domains created in cPanel → **Domains**:
  - `yourdomain.com` (web)
  - `api.yourdomain.com` (API)

> Passenger supports WebSockets, so Socket.io / WebRTC signaling works. If your
> host blocks WS, Socket.io automatically falls back to HTTP long-polling.

---

## 1. Create the PostgreSQL database

cPanel → **PostgreSQL Databases** (or **PostgreSQL Database Wizard**):

1. **Create a database** — e.g. name it `feater`. cPanel prefixes it with your
   account name, so the real name becomes something like `cpuser_feater`.
2. **Create a user** — e.g. `feateruser` (becomes `cpuser_feateruser`), with a
   strong password. Save it.
3. **Add the user to the database** and grant **ALL PRIVILEGES**.

Now build your connection string (used as `DATABASE_URL` in step 3). Because the
API runs on the same server, the host is `localhost` and no SSL is needed:

```
postgresql://cpuser_feateruser:PASSWORD@localhost:5432/cpuser_feater?schema=public
```

> Replace the user, password, and DB name with the real prefixed values. If the
> password contains `@ : / # ?` etc., URL-encode those characters.
> You do **not** run any SQL by hand — `prisma migrate deploy` (step 3) creates
> every table, enum, and index for you.

---

## 2. Upload the code

Put the whole repo on the server, e.g. under `~/feater`. Options:

- **Git (recommended):** cPanel → **Git Version Control** → Clone your repo to
  `~/feater`, or from Terminal: `git clone <your-repo-url> ~/feater`.
- **Zip upload:** compress the project, upload via **File Manager**, extract to
  `~/feater`.

Do **not** upload `node_modules` or `.next` — they are built on the server.

Final layout on the server:

```
~/feater/
├── apps/
│   ├── api/   ← Node app #1 (root = this folder)
│   └── web/   ← Node app #2 (root = this folder)
└── ...
```

---

## 3. Create the API Node.js app

cPanel → **Setup Node.js App** → **Create Application**:

- **Node.js version:** 20.x (or newer)
- **Application mode:** Production
- **Application root:** `feater/apps/api`
- **Application URL:** `api.yourdomain.com`
- **Application startup file:** `app.js`

Click **Create**. Then, in the app's **Environment variables** section, add the
values from [`apps/api/.env.production.example`](apps/api/.env.production.example):

```
DATABASE_URL   = postgresql://cpuser_feateruser:PASSWORD@localhost:5432/cpuser_feater?schema=public
NODE_ENV       = production
CORS_ORIGIN    = https://yourdomain.com
JWT_ACCESS_SECRET   = <long random string>
JWT_REFRESH_SECRET  = <different long random string>
JWT_ACCESS_TTL      = 15m
JWT_REFRESH_TTL     = 30d
OTP_TTL_SECONDS     = 300
SMTP_HOST = smtp.gmail.com
SMTP_PORT = 465
SMTP_USER = youraddress@gmail.com
SMTP_PASS = <gmail app password>
MAIL_FROM = Feater <youraddress@gmail.com>
```

> **Do not set `PORT`** — Passenger injects it and `src/main.ts` reads it.
> Generate secrets with `openssl rand -hex 32`.
> Alternatively, instead of the UI, copy `.env.production.example` to
> `apps/api/.env` and fill it in — NestJS loads it automatically.

### Build the API

Open the app's **Terminal** (the button copies a command that activates this
app's Node environment), then:

```bash
cd ~/feater/apps/api
npm install
npm run build            # prisma generate && nest build → dist/
npm run deploy:migrate   # prisma migrate deploy (creates all tables in your cPanel DB)
```

Back in **Setup Node.js App**, click **Restart**.

Verify: open `https://api.yourdomain.com/api/health` — you should get a healthy
JSON response. Swagger is at `https://api.yourdomain.com/api/docs`.

---

## 4. Create the Web Node.js app

cPanel → **Setup Node.js App** → **Create Application**:

- **Node.js version:** 20.x (or newer)
- **Application mode:** Production
- **Application root:** `feater/apps/web`
- **Application URL:** `yourdomain.com`
- **Application startup file:** `server.js`

Click **Create**.

### Set the build-time env, then build

Next.js **inlines `NEXT_PUBLIC_*` at build time**, so these must exist *before*
you build. The most reliable way is a file. In **File Manager** (or Terminal),
copy [`apps/web/.env.production.example`](apps/web/.env.production.example) to
`apps/web/.env.production` and set:

```
NEXT_PUBLIC_API_URL = https://api.yourdomain.com
# optional:
NEXT_PUBLIC_TURN_URL=...
NEXT_PUBLIC_TURN_USERNAME=...
NEXT_PUBLIC_TURN_CREDENTIAL=...
NEXT_PUBLIC_GIPHY_KEY=...
```

> `NEXT_PUBLIC_API_URL` has **no trailing slash and no `/api`** — the client adds
> `/api` for REST and connects Socket.io to this base.

Then, in the web app's **Terminal**:

```bash
cd ~/feater/apps/web
npm install
npm run build            # next build → .next/
```

Back in **Setup Node.js App**, click **Restart**.

Visit `https://yourdomain.com` — the landing page should load and be able to
sign up / log in against the API.

---

## 5. Post-deploy checklist

- [ ] `https://api.yourdomain.com/api/health` returns OK.
- [ ] Sign up with a real email → OTP arrives (SMTP configured).
- [ ] Log in, complete onboarding, upload a photo → it displays (served from
      `https://api.yourdomain.com/uploads/...`).
- [ ] Open Discover / Chats → live messaging works (Socket.io connected).
- [ ] Create a voice room in two browsers → audio + "Let in" approval works.
- [ ] Force HTTPS: cPanel → **Domains** → enable *Force HTTPS Redirect* on both
      domains. WebRTC (mic) and Socket.io require HTTPS in production.

---

## 6. Updating after a code change

```bash
cd ~/feater && git pull

cd apps/api && npm install && npm run build && npm run deploy:migrate
# → Setup Node.js App → API app → Restart

cd ../web && npm install && npm run build
# → Setup Node.js App → Web app → Restart
```

Only run `deploy:migrate` when the Prisma schema changed. Re-run the web build
whenever any `NEXT_PUBLIC_*` value changes.

---

## Troubleshooting

| Symptom | Fix |
| ------- | --- |
| Web loads but every API call fails (CORS) | `CORS_ORIGIN` on the **API** app must exactly equal the web origin, e.g. `https://yourdomain.com` (no trailing slash). Restart the API. |
| 502 / app won't start | Check the app's **stderr log** (path shown in the Node App panel). Usually a missing env var or a build that didn't run. Re-run `npm run build`. |
| API up but DB errors (P1000/P1001) | Verify `DATABASE_URL` — use the **prefixed** DB and user names (`cpuser_...`), host `localhost`, and make sure the user was added to the DB with ALL PRIVILEGES. No `sslmode` is needed for localhost. |
| `prisma migrate deploy` fails on permissions / creating types | The DB user needs ALL PRIVILEGES on the database (cPanel → PostgreSQL Databases → *Add User To Database*). Re-add it, then retry. |
| Photos upload but 404 on display | Confirm `NEXT_PUBLIC_API_URL` points at the API host and the API app restarted after build. Files live in `apps/api/uploads/`. |
| Calls connect same-network but not across networks | Add a TURN server via the `NEXT_PUBLIC_TURN_*` vars and rebuild the web app. |
| Socket.io keeps polling / disconnects | Host may block WebSockets; polling still works. Ask the host to allow WS upgrades on the API domain for best performance. |
| `NEXT_PUBLIC_*` change didn't take effect | Next.js bakes them at build time — rebuild the web app and restart. |
