Add AGENTS.md and deploy configs to the API repo.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,131 @@
|
|||||||
|
# AGENTS.md — SuperAdmin آبشده + همکار + خانگی
|
||||||
|
|
||||||
|
این فایل برای ادامه کار در Cursor است (از جمله Workspace سهپروژهای).
|
||||||
|
قبل از تغییر معماری یا اتصال API، این سند را بخوان.
|
||||||
|
|
||||||
|
## پروژهها
|
||||||
|
|
||||||
|
| نام | مسیر تقریبی | نقش |
|
||||||
|
|-----|-------------|-----|
|
||||||
|
| SuperAdminAbshode | `E:\projeha\SuperAdminAbshode` | کنترلپنل مرکزی شرکت |
|
||||||
|
| Hamkar | `E:\projeha\Hamkar` | محصول همکار (نسخههای فروشی) |
|
||||||
|
| Khanegi | `E:\projeha\Khanegi` (عمدتاً KhanegiModular) | محصول خانگی |
|
||||||
|
|
||||||
|
Workspace پیشنهادی: `E:\projeha\Abshode-suite.code-workspace`
|
||||||
|
|
||||||
|
## هدف کسبوکار
|
||||||
|
|
||||||
|
مدیر شرکت نرمافزاری است؛ محصولات بهصورت نسخه فروشی (white-label) فروخته میشوند.
|
||||||
|
نیاز اصلی: مدیریت متمرکز نسخهها، برند، ظاهر، پیامک، سرور/تمدید/پشتیبانی (جایگزین گوگلشیت).
|
||||||
|
|
||||||
|
## تصمیمهای قطعی تا الان
|
||||||
|
|
||||||
|
1. **استک سوپرادمین:** NestJS + Prisma + Vue 3 + Ant Design Vue + فونت Dana — نه Laravel.
|
||||||
|
2. **UI:** داشبورد نرم روشن، RTL، بدون سایدبار منو؛ کارتهای ماژول در صفحه اول.
|
||||||
|
3. **منبع حقیقت برند/ظاهر:** سوپرادمین و `GET /get_user` (نه SSH/DB برای روزمره).
|
||||||
|
4. **`/get_user` عمومی است** → رمز/گلوگاه SMS داخلش نرود.
|
||||||
|
5. **SMS:** پنل کامل داخل سوپرادمین ساخته میشود؛ **فعلاً پنل SMS داخل همکار/خانگی دست نخورده میماند** تا تست جواب بدهد؛ بعد حذف/غیرفعال.
|
||||||
|
6. **منبع حقیقت SMS (پیشنهاد قطعی):** کیف پول / تعرفه / مسدودسازی در سوپرادمین؛ ارسال همچنان با `SmsGatewayService` همان نسخه.
|
||||||
|
7. **مسئول فنی:** برای برند به DB لوکال نیاز نیست؛ اطلاعات رجیستری از `/get_user`؛ SMS سوپرادمین از صفر.
|
||||||
|
8. **برای اتصال دوطرفه واقعی** اپها به سوپرادمین، این پروژه باید روی سرور با دامنه HTTPS باشد. لوکال برای توسعه و push به نسخههای آنلاین کافی است.
|
||||||
|
9. **دیتابیس پروداکشن:** PostgreSQL (نه SQLite). دامنه هدف: `https://adm.montzar.ir` روی سرور مشترک montime؛ API روی پورت `3010`. جزئیات: `deploy/DEPLOY.md`.
|
||||||
|
|
||||||
|
## وضعیت فعلی کد سوپرادمین
|
||||||
|
|
||||||
|
### ساختار
|
||||||
|
- `apps/api` — NestJS + Prisma (**PostgreSQL**؛ تاریخچه SQLite در `prisma/migrations_sqlite_archive/`)
|
||||||
|
- `apps/web` — Vue 3 + Vite + Ant Design Vue
|
||||||
|
- ورود پیشفرض: موبایل `SEED_ADMIN_MOBILE` / `SEED_ADMIN_PASSWORD` (مثلاً `09128081392` / `Admin@12345`)
|
||||||
|
- دیپلوی: `deploy/` داخل همین ریپوی API (nginx + pm2 + راهنما)
|
||||||
|
|
||||||
|
### قابلیتهای پیادهشده
|
||||||
|
- Auth JWT، CRUD نسخهها (Tenant)، Audit
|
||||||
|
- مدیران سوپرادمین: نام / نامخانوادگی / موبایل / رمز؛ ورود با موبایل؛ صفحه `/admins`
|
||||||
|
- پیامک هشدار مدیران از API مرکزی اساماس رایگان (`CENTRAL_SMS_*` → `createsms`)؛ رویدادهای نسخه و کیف پول SMS
|
||||||
|
- پنل سرور: اختصاصی یا مدیریتشده؛ نام/مشخصات/قیمت/مدت (۱،۳،۶،۱۲ ماه)؛ هشدار SMS نزدیک انقضا (پیشفرض ۳ روز، روزانه تا تمدید)
|
||||||
|
- پنل افزونه: هر نسخه ۰..N افزونه (`PluginSubscription` + `PluginCharge`)؛ نام اجباری + مشخصات/قیمت/مدت ۱،۳،۶،۱۲ ماه؛ هشدار SMS مثل سرور؛ صفحات `/plugins` و `/plugins/:tenantId`
|
||||||
|
- `GET /get_user` با تطبیق دامنه اصلی + آرایه `domains` + `app_ui_config` برای خانگی
|
||||||
|
- `GET /get_version?domain=` — ورژن همان نسخه فروشی (`Tenant.appVersion`)؛ تنظیم از صفحه مدیریت نسخه؛ جایگزین `nerkh.gold/get_version`
|
||||||
|
- ایمپورت نسخهها از `apps/api/prisma/data/users.json` (`npm run prisma:import-users`)
|
||||||
|
- تشخیص محصول: `app.` / `khanegi.` → خانگی؛ `hamkar.` → همکار؛ overrides دستی در اسکریپت ایمپورت
|
||||||
|
- پنل SMS مستقل سوپرادمین: `SmsAccount` + `SmsLedger` (موجودی، شارژ، تعرفه، بلاک، آستانههای رنگی، گلوگاه)
|
||||||
|
- رنگ موجودی: سبز >100000، زرد 10000–100000، قرمز <10000 (ریال)
|
||||||
|
- داشبورد: ۵ نسخه کمموجودی؛ صفحه SMS: کارتها → جزئیات در `/sms/:tenantId`
|
||||||
|
- ظاهر اپ خانگی: صفحه `UiConfigPage` برای `appUiConfig`؛ بکفیل از رجیستری/`users.json` با `npm run prisma:backfill-appearance`؛ در فرانت: `showNotifications` / `header.visible` / `startRoute`
|
||||||
|
- ظاهر اپ همکار: `/versions/:id/ui-hamkar`؛ رنگها + حالت رجیستری (`registryMode`)؛ `settingsManaged` باید true باشد تا `ui_settings` بیاید (وگرنه لاراول میماند)
|
||||||
|
|
||||||
|
### مهم
|
||||||
|
- موجودی SMS اولیه **دمو** بود تا رنگها دیده شوند؛ منبع واقعی همکار/خانگی نیست مگر بعداً وصل شود.
|
||||||
|
- چند دامنه دستی اصلاح شده (مثل 24gold.ir، limangold.ir، vahid.gold).
|
||||||
|
- چند نسخه با تأیید کاربر از همکار به خانگی منتقل شدهاند (لیست در `FORCE_KHANEGI` داخل `import-users.ts`).
|
||||||
|
|
||||||
|
## معماری هدف اتصال به همکار/خانگی
|
||||||
|
|
||||||
|
دو جهت API:
|
||||||
|
|
||||||
|
### A) اپها → سوپرادمین
|
||||||
|
- `GET /get_user` — برند و ظاهر (موجود)
|
||||||
|
- بعدی: `GET/POST` وضعیت SMS (`status` / `consume`) با `remoteApiToken`
|
||||||
|
|
||||||
|
### B) سوپرادمین → اپها
|
||||||
|
- `GET/POST /super/settings` روی Laravel هر نسخه — تنظیمات مدیریتی
|
||||||
|
- اختیاری: reload برند / health
|
||||||
|
|
||||||
|
احراز هویت: `Tenant.remoteApiToken` در سوپرادمین + همان توکن روی نسخه.
|
||||||
|
|
||||||
|
### منبع حقیقت پیشنهادی
|
||||||
|
|
||||||
|
| موضوع | منبع |
|
||||||
|
|------|------|
|
||||||
|
| برند / دامنه / لوگو / رنگ | سوپرادمین `/get_user` |
|
||||||
|
| `app_ui_config` خانگی | سوپرادمین → مصرف در فرانت خانگی |
|
||||||
|
| ورژن اپ / رفرش اجباری کش | سوپرادمین `/get_version` (per tenant: `Tenant.appVersion`) |
|
||||||
|
| کیف پول / تعرفه / بلاک SMS | سوپرادمین |
|
||||||
|
| ارسال SMS | `SmsGatewayService` همان نسخه |
|
||||||
|
| پنل SMS داخل محصولات | فعلاً دستنخورده |
|
||||||
|
|
||||||
|
## فازهای بعدی (به ترتیب)
|
||||||
|
|
||||||
|
1. **دیپلوی سوپرادمین** روی `adm.montzar.ir` (migrate + pm2 + nginx) — DB `superadmin` آماده است.
|
||||||
|
2. **پایلوت برند:** یک نسخه تست فقط از `/get_user` سوپرادمین بوت شود.
|
||||||
|
3. **ظاهر خانگی:** مصرف کامل `app_ui_config` در خانگی.
|
||||||
|
4. **API `/super/*` روی Laravel همکار و خانگی** با middleware توکن.
|
||||||
|
5. **SMS دوطرفه:** status/consume در سوپرادمین + هوک قبل/بعد ارسال در محصولات.
|
||||||
|
6. بعد از پایداری: کاهش/حذف پنل SMS داخلی محصولات.
|
||||||
|
|
||||||
|
## قواعد کار ایجنت
|
||||||
|
|
||||||
|
- بدون درخواست صریح کاربر: commit نکن، force push نکن، پنل SMS همکار/خانگی را حذف نکن.
|
||||||
|
- تغییرات همکار و خانگی را فقط وقتی کاربر صریحاً خواست؛ فعلاً اولویت سوپرادمین + طراحی قرارداد API است.
|
||||||
|
- در Workspace چندریشه: قبل از ادیت بگو در کدام ریشه کار میکنی (`SuperAdminAbshode` / `Hamkar` / `Khanegi`).
|
||||||
|
- **امنیت (همیشه):** secret / توکن / رمز را در UI، لاگ، `.env.example`، commit، یا پاسخ چت قرار نده؛ fallback هاردکد برای secret نگذار؛ رمز را فقط hash ذخیره کن و در API برنگردان؛ ورودیها را validate/normalize کن (مثل موبایل).
|
||||||
|
- **تاریخ/ساعت:** همیشه شمسی (جلالی) و به وقت ایران (`Asia/Tehran`) — انتخابگر تاریخ شمسی و فرمت نمایش از `utils/datetime` / `iran-time.util`.
|
||||||
|
- رمزها و secretهای `users.json` و `CENTRAL_SMS_SECRET` را وارد UI/لاگ عمومی نکن.
|
||||||
|
- Prisma روی ویندوز: اگر `EPERM` روی `query_engine`، اول API را متوقف کن بعد `prisma generate`.
|
||||||
|
|
||||||
|
## اجرای لوکال
|
||||||
|
|
||||||
|
`DATABASE_URL` باید PostgreSQL باشد (Docker لوکال یا DB سرور). نمونه: `.env.example`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd E:\projeha\SuperAdminAbshode\apps\api
|
||||||
|
npx prisma migrate deploy
|
||||||
|
npm run start:dev
|
||||||
|
|
||||||
|
cd E:\projeha\SuperAdminAbshode\apps\web
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
- Web: http://localhost:5173/
|
||||||
|
- API: http://localhost:3001/
|
||||||
|
|
||||||
|
## چت اول در Workspace جدید — پیشنهاد متن
|
||||||
|
|
||||||
|
> ادامه کار سوپرادمین آبشده با همکار و خانگی.
|
||||||
|
> حتماً `SuperAdminAbshode/AGENTS.md` (یا `AGENTS.md` داخل ریپوی API) را بخوان.
|
||||||
|
> تصمیمها و وضعیت فعلی همانجاست؛ از صفر مشورت نکن مگر برای مرحله بعد (پایلوت API / دیپلوی).
|
||||||
|
|
||||||
|
## تاریخ بهروزرسانی
|
||||||
|
|
||||||
|
2026-07-30 — Prisma → PostgreSQL؛ DB `superadmin` روی سرور montime؛ deploy برای `adm.montzar.ir`.
|
||||||
|
2026-07-25 — جمعبندی گفتگوهای ساخت پنل، ایمپورت نسخهها، SMS مستقل، و نقشه اتصال API.
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# 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)
|
||||||
|
3. Confirm uploads/logo URLs use `PUBLIC_API_URL`
|
||||||
|
|
||||||
|
## 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`).
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* PM2 — SuperAdmin API on shared montime host.
|
||||||
|
* Port 3010 avoids clash with montime-api (:3000) and forisanad (:3001).
|
||||||
|
*
|
||||||
|
* Usage (on server, as montime):
|
||||||
|
* pm2 start /var/www/superadmin/api/deploy/ecosystem.config.cjs
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'superadmin-api',
|
||||||
|
cwd: '/var/www/superadmin/api',
|
||||||
|
script: 'dist/main.js',
|
||||||
|
instances: 1,
|
||||||
|
exec_mode: 'fork',
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
PORT: '3010',
|
||||||
|
},
|
||||||
|
max_memory_restart: '400M',
|
||||||
|
time: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# Place under /etc/nginx/sites-available/adm.montzar.ir
|
||||||
|
# SSL: assume Certbot already issued for adm.montzar.ir (or enable after first HTTP).
|
||||||
|
#
|
||||||
|
# Single domain: SPA at / + Nest API under /api + public get_user/get_version + uploads.
|
||||||
|
|
||||||
|
upstream superadmin_api {
|
||||||
|
server 127.0.0.1:3010;
|
||||||
|
keepalive 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name adm.montzar.ir;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
server_name adm.montzar.ir;
|
||||||
|
|
||||||
|
# Certbot paths — adjust if different on this host
|
||||||
|
ssl_certificate /etc/letsencrypt/live/adm.montzar.ir/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/adm.montzar.ir/privkey.pem;
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||||
|
|
||||||
|
root /var/www/superadmin/web/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
client_max_body_size 20M;
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://superadmin_api;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /get_user {
|
||||||
|
proxy_pass http://superadmin_api;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /get_version {
|
||||||
|
proxy_pass http://superadmin_api;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /uploads/ {
|
||||||
|
proxy_pass http://superadmin_api;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user