2026-07-30 19:21:30 +03:30
|
|
|
# Deploy — SuperAdmin on shared montime host
|
|
|
|
|
|
|
|
|
|
Host: `185.50.38.53` (SSH port `3031`)
|
|
|
|
|
Domain: `https://adm.montzar.ir`
|
|
|
|
|
DB: Postgres `superadmin` (owner `montime`) — already created
|
|
|
|
|
API port: `3010` (3000=montime, 3001=forisanad)
|
|
|
|
|
|
|
|
|
|
## Layout on server
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
/var/www/superadmin/
|
|
|
|
|
api/ # clone of controlPanel/api.git
|
|
|
|
|
deploy/ # nginx + pm2 + this guide (in api repo)
|
|
|
|
|
web/ # clone of controlPanel/web.git (Vue dist)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 1) Clone / pull
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
sudo mkdir -p /var/www/superadmin
|
|
|
|
|
sudo chown montime:montime /var/www/superadmin
|
|
|
|
|
|
|
|
|
|
cd /var/www/superadmin
|
|
|
|
|
git clone https://get.feep.ir/controlPanel/api.git api
|
|
|
|
|
git clone https://get.feep.ir/controlPanel/web.git web
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Later updates: `git pull` in each folder.
|
|
|
|
|
|
|
|
|
|
## 2) API `.env`
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd /var/www/superadmin/api
|
|
|
|
|
cp .env.example .env
|
|
|
|
|
nano .env
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Required:
|
|
|
|
|
|
|
|
|
|
```env
|
|
|
|
|
NODE_ENV=production
|
|
|
|
|
PORT=3010
|
|
|
|
|
DATABASE_URL="postgresql://montime:YOUR_PASSWORD@127.0.0.1:5432/superadmin?schema=public"
|
|
|
|
|
JWT_SECRET="long-random-production-secret"
|
|
|
|
|
JWT_EXPIRES_IN="7d"
|
|
|
|
|
CORS_ORIGIN="https://adm.montzar.ir"
|
|
|
|
|
PUBLIC_API_URL="https://adm.montzar.ir"
|
|
|
|
|
SEED_ADMIN_MOBILE="09128081392"
|
|
|
|
|
SEED_ADMIN_PASSWORD="change-me"
|
|
|
|
|
# CENTRAL_SMS_* as needed
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Password = same Postgres password that works for `psql -h 127.0.0.1 -U montime -d superadmin`.
|
|
|
|
|
|
|
|
|
|
## 3) Install, migrate, build, seed
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd /var/www/superadmin/api
|
|
|
|
|
npm ci
|
|
|
|
|
npx prisma generate
|
|
|
|
|
npx prisma migrate deploy
|
|
|
|
|
npm run build
|
|
|
|
|
npm run prisma:seed
|
|
|
|
|
# optional first import:
|
|
|
|
|
# npm run prisma:import-users
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 4) PM2
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
pm2 start /var/www/superadmin/api/deploy/ecosystem.config.cjs
|
|
|
|
|
pm2 save
|
|
|
|
|
pm2 status
|
|
|
|
|
curl -s http://127.0.0.1:3010/api/health || true
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 5) Web build
|
|
|
|
|
|
|
|
|
|
Same-origin: leave `VITE_API_BASE` unset (defaults to `/api`).
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd /var/www/superadmin/web
|
|
|
|
|
npm ci
|
|
|
|
|
npm run build
|
|
|
|
|
# dist → /var/www/superadmin/web/dist
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 6) Nginx
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
sudo cp /var/www/superadmin/api/deploy/nginx-adm.montzar.ir.conf /etc/nginx/sites-available/adm.montzar.ir
|
|
|
|
|
sudo ln -sf /etc/nginx/sites-available/adm.montzar.ir /etc/nginx/sites-enabled/
|
|
|
|
|
sudo nginx -t && sudo systemctl reload nginx
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
SSL: if Certbot already issued for `adm.montzar.ir`, paths in the conf should match. Otherwise:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
sudo certbot --nginx -d adm.montzar.ir
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 7) Smoke
|
|
|
|
|
|
|
|
|
|
1. Open `https://adm.montzar.ir` → login
|
|
|
|
|
2. `https://adm.montzar.ir/get_user?domain=montpar.ir` (or any known domain)
|
2026-08-17 20:14:17 +03:30
|
|
|
3. `https://adm.montzar.ir/get_settings?domain=k.montzar.ir` (nginx must proxy `/get_settings` like `/get_user`)
|
|
|
|
|
4. Confirm uploads/logo URLs use `PUBLIC_API_URL`
|
2026-07-30 19:21:30 +03:30
|
|
|
|
2026-08-11 21:34:02 +03:30
|
|
|
## 8) Migrations with logical replication (failover replicas)
|
|
|
|
|
|
|
|
|
|
`superadmin_pub` streams rows to the failover hosts (`adm.montech.ir`, `adm.montest.ir`).
|
|
|
|
|
Logical replication does **not** carry DDL: a migration that adds a column on the
|
|
|
|
|
publisher makes every subscriber fail with `missing replicated columns` and the
|
|
|
|
|
subscription stalls until that column exists there too. Because `_prisma_migrations`
|
|
|
|
|
is replicated, `prisma migrate deploy` on a subscriber wrongly reports
|
|
|
|
|
"No pending migrations".
|
|
|
|
|
|
|
|
|
|
So never run `migrate deploy` alone. On the publisher host:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cp deploy/replicas.env.example deploy/replicas.env # once; add real DSNs
|
|
|
|
|
bash deploy/sync-replica-schema.sh --init # once, when schemas already match
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
For every release:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npm run replicas:sync # DDL to each replica first, then migrate deploy here
|
|
|
|
|
npm run replicas:check # subscription state + columns missing on any replica
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Keep migrations schema-only. Data backfills would run once per replica and then
|
|
|
|
|
again through replication, so apply those on the publisher by hand.
|
|
|
|
|
|
2026-07-30 19:21:30 +03:30
|
|
|
## Local development note
|
|
|
|
|
|
|
|
|
|
Prisma provider is **PostgreSQL** only. Local options:
|
|
|
|
|
|
|
|
|
|
- Docker: `docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=superadmin postgres:16`
|
|
|
|
|
- Or point `DATABASE_URL` at the server DB only for short tests (prefer local DB)
|
|
|
|
|
|
|
|
|
|
SQLite history is kept under `prisma/migrations_sqlite_archive/` (reference only; not applied by `migrate deploy`).
|