# JUNX DESIGN — TENTEN cPanel deployment guide

**Frontend:** `https://junx-test.yantft.online`  
**API:** `https://api-junx-test.yantft.online`  
**Status:** package preparation only. No files have been uploaded and no app has been deployed.

## Production environment

The source uses `NEXT_PUBLIC_API_URL`; API calls append paths such as `/contact` and `/portfolio/...` to that base. Set the value with `/api`:

| Variable | Value |
|---|---|
| `NODE_ENV` | `production` |
| `NEXT_PUBLIC_SITE_URL` | `https://junx-test.yantft.online` |
| `NEXT_PUBLIC_API_URL` | `https://api-junx-test.yantft.online/api` |
| `NEXT_PUBLIC_MEDIA_ORIGIN` | Leave unset while media is served from the API host. Set only if image URLs use a separate HTTPS host. |
| `PORT` | Do not set; CloudLinux/Passenger supplies it. |

Do not add backend secrets, database credentials, email credentials, or `.env` files to the frontend app or ZIP.

## Prepare the CloudLinux Node.js application

In cPanel → **Setup Node.js App** / **Node.js Selector**, create an application with:

| Setting | Value |
|---|---|
| Node.js version | `24.21.0` |
| Application mode | `Production` |
| Application root | `junx-frontend` (private directory relative to the account home; keep outside `public_html`) |
| Application URL | `junx-test.yantft.online` at `/` |
| Application startup file | `app.js` |

Set `NODE_ENV`, `NEXT_PUBLIC_SITE_URL`, and `NEXT_PUBLIC_API_URL` in the application settings and save. Set `NEXT_PUBLIC_MEDIA_ORIGIN` only if image URLs use a separate host. Do not define `PORT` manually. If an application is already mapped to this domain, review its current configuration and content first; this package has not been deployed over it.

## Upload and build without SSH

1. Open **File Manager** and create the private `junx-frontend` application root if it does not exist.
2. Upload `junx-frontend-cpanel-production.zip` into that directory and extract it there. The ZIP has project files at its top level, including `package.json`, `package-lock.json`, `app.js`, `app/`, `public/`, and `scripts/`.
3. In Node.js Selector, confirm the selected application root and environment variables, then click **Run NPM Install**.
4. To make sure build-time TypeScript dependencies are installed even if the panel's install runs with production-only settings, click **Run JS Script**, choose `install:cpanel`, and run it once. It runs `npm install --include=dev` from the application root. This does not run at Passenger startup.
5. In **Run JS Script**, run `build:cpanel`. This validates both public URLs, runs the optimized Next.js production build on the hosting Linux/Node environment, and records the URL marker required by `app.js`.
6. Confirm the script completes and `.next/BUILD_ID` exists in File Manager. Do not start the app if the build script failed.
7. Confirm the application settings still use startup file `app.js`, mode `Production`, Node `24.21.0`, and the exact same `NEXT_PUBLIC_*` values used for build. Restart the application in Node.js Selector.

CloudLinux documents **Run JS Script** as running a named command from `package.json`'s scripts section, and its Node.js Selector exposes app root, startup file, environment variables, NPM install, and restart controls: [CloudLinux Manager UI](https://docs.cloudlinux.com/cloudlinuxos/lve_manager/#node-js-selector-client-plugin). TENTEN's cPanel help also describes creating the app in **Setup NodeJS App**: [TENTEN NodeJS on cPanel](https://help.tenten.vn/cai-dat-nodejs-app-tren-cpanel/).

## Restart and smoke checks

Use the application's **Restart** action in Node.js Selector. `app.js` checks production URLs, `PORT`, build ID and build/runtime URL consistency, then passes requests to the Next.js server. Do not run `npm start` alongside Passenger.

After restart, check these URLs in a browser:

- `https://junx-test.yantft.online/`
- `https://junx-test.yantft.online/portfolio`
- `https://junx-test.yantft.online/admin`
- `https://junx-test.yantft.online/robots.txt`
- `https://junx-test.yantft.online/sitemap.xml`
- `https://junx-test.yantft.online/og`

Expected: pages return HTTP 200; `/robots.txt` and `/sitemap.xml` contain the frontend hostname and no localhost; `/og` returns `image/png`; homepage portfolio data and topic URLs load from the API. Admin page returning 200 does not mean admin authentication was tested. Do not test contact by submitting real personal information unless an authorized staging submission is intended.

For contact form browser requests, API CORS must allow the exact origin `https://junx-test.yantft.online`. The API preflight was read-only checked before deploy and returned 204 with the matching `Access-Control-Allow-Origin`.

## cPanel build limitations

The ZIP intentionally excludes `.next` and `node_modules`: this Mac is Darwin ARM64 and cannot produce the hosting's Linux Node 24 dependency tree. Build in Node.js Selector after upload so native/runtime packages and the Next server output are produced in the hosting environment.

`npm run build:cpanel` already passed locally using the supplied real URLs on Node `v25.9.0`; this validates source/build configuration, not the exact Node `24.21.0` hosting runtime. The cPanel run remains required.
