# Deploy Twenzetu API to cPanel (twenzetu.liwaletech.co.tz)

Target: [http://twenzetu.liwaletech.co.tz/](http://twenzetu.liwaletech.co.tz/) with **Setup Node.js App** + **PostgreSQL**.

Redis is optional (the API falls back to in-memory geo). Socket.IO may use HTTP long-polling if WebSockets are restricted.

## 1. Create PostgreSQL database

In cPanel → **PostgreSQL Databases**:

1. Create a database (e.g. `user_twenzetu`).
2. Create a user with a strong password.
3. Add the user to the database with **ALL PRIVILEGES**.
4. Note: host (usually `localhost`), port (`5432`), database name, username, password.

Build `DATABASE_URL`:

```text
postgresql://DB_USER:DB_PASSWORD@localhost:5432/DB_NAME
```

URL-encode special characters in the password if needed.

If your host requires SSL for Postgres, set `DB_SSL=true` (see env section).

**cPanel note:** Many hosts reject non-SSL connections with:

`no pg_hba.conf entry for host "127.0.0.1", user "...", database "...", SSL off`

Fix: set `DB_SSL=true` (or rely on production default SSL). Confirm the DB name matches cPanel (often prefixed, e.g. `liwalete_twenzetu`).

## 2. Create the Node.js application

In cPanel → **Setup Node.js App**:

| Field | Value |
|-------|--------|
| Node.js version | **18** or **20** LTS |
| Application mode | **Production** |
| Application root | e.g. `twenzetu-api` (under your home, or path the UI creates) |
| Application URL | `twenzetu.liwaletech.co.tz` |
| Application startup file | **`server.js`** |

Save / Create. Copy the **virtual environment activate** command shown by cPanel (something like):

```bash
source /home/USER/nodevenv/twenzetu-api/20/bin/activate
cd ~/twenzetu-api
```

## 3. Upload the backend

Upload the contents of the local `backend/` folder into the **application root** so these exist on the server:

- `package.json`
- `server.js`
- `tsconfig.json`
- `.sequelizerc`
- `src/` (including `src/db/migrations` and `src/db/seeders`)

Do **not** upload your local `.env` with development secrets. Prefer environment variables in the Node.js App UI.

Exclude local junk if zipping: `node_modules/`, `dist/`, `.env`.

## 4. Environment variables

In Setup Node.js App → **Environment variables** (or create `.env` in the app root with the same keys):

```env
NODE_ENV=production
PORT=

DATABASE_URL=postgresql://DB_USER:DB_PASSWORD@localhost:5432/DB_NAME
DB_USER=DB_USER
DB_PASSWORD=DB_PASSWORD
DB_HOST=localhost
DB_PORT=5432
DB_NAME=DB_NAME
DB_SSL=true

JWT_ACCESS_SECRET=replace-with-long-random-string
JWT_REFRESH_SECRET=replace-with-another-long-random-string
JWT_ACCESS_EXPIRES=15m
JWT_REFRESH_EXPIRES=7d

OTP_TTL_SECONDS=300
OTP_MAX_ATTEMPTS=5
OTP_DEV_MODE=false

CORS_ORIGIN=*
PUBLIC_API_URL=https://twenzetu.liwaletech.co.tz
UPLOAD_DIR=uploads
REDIS_URL=

ACCEPTANCE_TIMER_SECONDS=30
DISPATCH_RADIUS_KM=10
GOOGLE_MAPS_API_KEY=
FCM_SERVER_KEY=
```

Notes:

- Leave `PORT` empty if cPanel injects it automatically; otherwise use the port shown in the Node.js App UI.
- Set `DB_SSL=true` on cPanel (required when migrate/errors show `SSL off` / `pg_hba.conf`). Production defaults SSL on unless `DB_SSL=false`.
- `OTP_DEV_MODE=false` in production (no OTP printed to logs; wire SMS later).
- Never commit real JWT secrets.

See also [`.env.example`](.env.example) and [`.env.cpanel.example`](.env.cpanel.example).

## 5. Install, build, migrate, seed

In **Terminal** / SSH, activate the Node venv, then from the application root:

```bash
source /home/USER/nodevenv/twenzetu-api/20/bin/activate
cd ~/twenzetu-api

npm install
npm run build
npm run db:migrate
npm run db:seed
mkdir -p uploads
chmod 755 uploads
```

`npm run build` compiles TypeScript to `dist/`. `server.js` loads `dist/index.js`.

Seed accounts (change passwords after first login in production):

| Role | Phone | Password |
|------|--------|----------|
| Admin | `+255700000001` | `Admin@123` |
| Rider | `+255711111111` | `Rider@123` |
| Driver | `+255722222222` | `Driver@123` |

Dev OTP when `OTP_DEV_MODE=true` only: `123456`.

## 6. Start / restart

In Setup Node.js App, click **Restart**.

Confirm startup file remains **`server.js`**.

## 7. Verify

1. Open `http://twenzetu.liwaletech.co.tz/api/docs` (or `https://…` after AutoSSL). Raw OpenAPI JSON: `/api/docs.json`.
2. `GET http://twenzetu.liwaletech.co.tz/api/v1/categories` → seeded vehicle categories.
3. Login via `POST /api/v1/auth/login` with a seed account.
4. Enable AutoSSL / Let’s Encrypt for HTTPS when ready.

### Flutter app

```bash
flutter run --dart-define=API_BASE_URL=https://twenzetu.liwaletech.co.tz
```

Use `http://` only until SSL is active. Prefer HTTPS on devices.

### Admin (Next.js)

Point the admin API base URL to the same host (e.g. `https://twenzetu.liwaletech.co.tz`).

## Troubleshooting

### 503 Service Unavailable (LiteSpeed)

LiteSpeed shows **503** when the Node process is stopped, crashed on boot, or not listening the way Passenger expects.

Work through this checklist in order:

1. **Setup Node.js App**
   - Application status = **Running** (click **Restart** after any file/env change).
   - Application startup file = **`server.js`** (not `dist/index.js` alone unless you intend that).
   - Application URL matches `twenzetu.liwaletech.co.tz`.
2. **Build artifacts on the server** (Terminal / SSH, with nodevenv activated):

```bash
source /home/USER/nodevenv/twenzetu-api/20/bin/activate
cd ~/twenzetu-api   # your application root
npm install
npm run build
test -f dist/index.js && echo "dist OK" || echo "dist MISSING"
npm run db:migrate
mkdir -p uploads
```

3. **Environment variables** (Node.js App UI or `.env`):
   - `DATABASE_URL`, `DB_USER`, `DB_PASSWORD`, `DB_HOST`, `DB_PORT`, `DB_NAME`
   - `JWT_ACCESS_SECRET`, `JWT_REFRESH_SECRET`
   - `NODE_ENV=production`
   - `PUBLIC_API_URL=https://twenzetu.liwaletech.co.tz`
   - `DB_SSL=true` (required on most cPanel Postgres; error `pg_hba ... SSL off` means SSL is off)
   - Leave `PORT` empty if cPanel injects it (invalid/empty PORT is ignored and falls back to 4000 in standalone mode).
   - Set `DB_SSL=false` only if your Postgres explicitly allows non-SSL local connections.
4. **Read stderr** in Setup Node.js App (or the app log). Look for:
   - `Missing dist/index.js` → run `npm run build`
   - `startup failed` / Sequelize / password authentication → fix Postgres URL and grants
   - `listening via Phusion Passenger` or `listening on http://0.0.0.0:…` → app started successfully
5. **Verify endpoints**
   - `https://twenzetu.liwaletech.co.tz/health` → `{"ok":true,"service":"twenzetu-api"}`
   - Then `https://twenzetu.liwaletech.co.tz/api/docs`

| Symptom | Check |
|---------|--------|
| App won’t start | `npm run build` succeeded; `dist/index.js` exists; startup file is `server.js` |
| DB connection / `SSL off` / `pg_hba.conf` | Set `DB_SSL=true`, restart; verify `DATABASE_URL` user/db name from cPanel |
| 503 / Passenger error | Follow the 503 checklist above; Restart Node app; read stderr |
| Empty site directory listing | Node app URL not mapped to domain, or app stopped |
| Socket.IO issues | Expected on some shared hosts; clients fall back to polling |
| Migrate fails | Activate nodevenv first; `sequelize-cli` must be installed (`npm install`) |

## Redeploy updates

```bash
source /home/USER/nodevenv/twenzetu-api/20/bin/activate
cd ~/twenzetu-api
# upload changed files
npm install
npm run build
npm run db:migrate
# Restart in cPanel Node.js UI
```
