steelforesight/README_FA.md

262 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# راهنمای جامع پروژه اندیشکده فولاد آینده (Andishkade Foolad)
این سند، راهنمای فنی و معماریِ پروژه **اندیشکده فولاد آینده** است — یک پلتفرم تحلیلیِ صنعت فولاد، شاملِ یک وب‌سایتِ محتوایی و یک پنلِ مدیریت/بک‌اند. در این سند ساختار پوشه‌ها، پشته‌ی فناوری، پایگاه داده، احراز هویت، قابلیت‌ها و نحوه‌ی استقرار توضیح داده شده است.
---
## فهرست مطالب
- [۱. ساختار کلی پروژه](#۱-ساختار-کلی-پروژه)
- [۲. فرانت‌اند (`frontend/`)](#۲-فرانت‌اند-frontend)
- [۳. پنل مدیریت و بک‌اند (`panel/`)](#۳-پنل-مدیریت-و-بک‌اند-panel)
- [۴. پایگاه داده](#۴-پایگاه-داده)
- [۵. احراز هویت و اعضا](#۵-احراز-هویت-و-اعضا)
- [۶. اتصال فرانت‌اند به پنل (Wiring)](#۶-اتصال-فرانت‌اند-به-پنل-wiring)
- [۷. فهرست APIها](#۷-فهرست-apiها)
- [۸. استقرار (Deployment)](#۸-استقرار-deployment)
---
## ۱. ساختار کلی پروژه
پروژه یک **مونوریپو** با دو اپلیکیشنِ مستقل و کنارهم (sibling) است که **هیچ build یا وابستگیِ مشترکی** ندارند؛ فرانت‌اند فقط در زمانِ اجرا (runtime) و از طریق متغیر `VITE_PANEL_API` با پنل حرف می‌زند.
```
andishkade-foolad/
├── frontend/ # وب‌سایت عمومی — Vite + React 19 + TypeScript
│ ├── src/
│ │ ├── app/ # مسیریابی (router) و قالب اصلی (RootLayout)
│ │ ├── components/ # کامپوننت‌های اشتراکی و UI
│ │ ├── context/ # کانتکست‌ها: زبان (LangContext) و احراز هویت (AuthContext)
│ │ ├── content/ data/ # داده‌های اولیه/ماک + ماژول‌های bootstrap که از پنل واکشی می‌کنند
│ │ └── pages/ # صفحات سایت
│ ├── public/ # دارایی‌های استاتیک، فونت‌ها، manifest و service worker (PWA)
│ ├── index.html
│ ├── vite.config.ts tsconfig*.json eslint.config.js
│ ├── Dockerfile nginx.conf liara.json # استقرار به‌صورت سرور استاتیک Nginx روی پورت ۷۸۶۰
│ └── package.json
├── panel/ # بک‌اند (Express API) + پنلِ مدیریت (CMS) — یک اپ واحد
│ ├── server.js # سرور و همه‌ی Routeهای API
│ ├── db.js # اتصال PostgreSQL + facade شبیه better-sqlite3 + مپ ردیف‌ها
│ ├── public/ # رابط کاربری پنل (SPA با Vanilla JS، بدون build)
│ ├── uploads/ # آپلودِ محلی (در صورت نبودِ S3)
│ ├── liara.json
│ └── package.json
├── docker-compose.yml # اجرای لوکالِ فرانت (context: ./frontend)
├── CLAUDE.md README.md README_FA.md SECURITY.md design-system.md
```
> **نکته:** پنل **هم بک‌اندِ API است و هم CMS** (رابطِ مدیریت را از `panel/public/` سرو می‌کند). این دو به‌هم گره خورده‌اند و یک اپلیکیشنِ واحدند.
### نمودار معماری
```
┌──────────────────────────┐
│ مرورگرِ کاربر │
└───────────┬──────────────┘
صفحاتِ سایت │ │ پنلِ مدیریت (ادمین)
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────────┐
│ FRONTEND (اپِ Liara: │ │ PANEL (اپِ Liara: │
│ steelforesight) │ │ cms-steelforesight) │
│ Nginx → فایل‌های استاتیکِ │ │ Express (server.js) │
│ dist/ (پورت ۷۸۶۰) │ │ + رابطِ CMS از panel/public/ │
│ React 19 / Vite │ │ │
└───────────┬───────────────┘ └──────┬───────────┬────────┬───┘
│ fetch (runtime) │ │ │
│ VITE_PANEL_API ─────────┘ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ REST /api │ │ PostgreSQL │ │ S3 Storage │ │ Kavenegar SMS │
│ (JSON) │ │ (Liara) │ │ (Liara) │ │ OpenAI/Claude │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
```
- **دو اپِ کاملاً جدا:** هرکدام Dockerfile/استقرارِ خودش را دارد و جداگانه روی Liara مستقر می‌شود. هیچ کدِ مشترکی بین `frontend/` و `panel/` import نمی‌شود.
- **زمانِ build (فرانت):** مقدارِ `VITE_PANEL_API` در زمانِ `vite build` داخلِ باندل تزریق می‌شود (نه در زمانِ اجرا). یعنی آدرسِ پنل در فایل‌های استاتیکِ خروجی ثابت می‌شود.
- **زمانِ اجرا:** مرورگر فایل‌های استاتیک را از فرانت می‌گیرد، سپس مستقیماً با `fetch` به `https://cms-steelforesight.liara.run/api/...` وصل می‌شود (cross-origin، با `credentials: 'include'` برای کوکیِ نشست). CORS در پنل با `ALLOWED_ORIGINS` کنترل می‌شود.
- **پنل ↔ سرویس‌ها:** پنل تنها مؤلفه‌ای است که به PostgreSQL، object storageِ S3، پیامکِ کاوه‌نگار و APIهای هوش مصنوعی وصل می‌شود؛ فرانت هیچ‌وقت مستقیماً با این‌ها حرف نمی‌زند.
### لایه‌بندیِ فرانت‌اند (jریانِ یک درخواست)
```
main.tsx → bootstrap*() → fetch(VITE_PANEL_API + /api/...) → پر کردنِ ماژول‌های content/data
│ │
│ (در صورت خطا/آفلاین: fallback به دادهٔ ایستا)
RouterProvider → RootLayout (Header / Footer / Lenis / بومی‌سازِ ارقام / ردیابِ فعالیت)
صفحه (src/pages/*) → useLang() برای fa/en · useAuth() برای نشستِ عضو
```
### لایه‌بندیِ پنل (jریانِ یک درخواست)
```
درخواست → helmet → CORS(ALLOWED_ORIGINS) → cookieParser → rate-limit
→ میدلورِ احراز هویت (authRequired برای ادمین / memberRequired برای عضو)
→ هندلرِ Route → db.prepare(sql).get/all/run() ↔ PostgreSQL
→ (آپلود: multer → sharp/WebP → S3 یا دیسک)
→ پاسخِ JSON
```
---
## ۲. فرانت‌اند (`frontend/`)
پورتالِ محتواییِ فارسی‌محور (Persian-first)، دوزبانه (fa/en) و RTL با انیمیشن‌های غنی.
### پشته‌ی فناوری
- **هسته:** React 19 + TypeScript.
- **بیلد:** Vite (HMR در توسعه، خروجی بهینه در پروداکشن). اعتبارسنجیِ سریع: `npx tsc -b --noEmit`.
- **استایل:** عمدتاً `style` اینلاین + کلاس‌های Tailwind CSS v4 برای واکنش‌گرایی (`max-md:` …) + متغیرهای CSS در `src/index.css`. رنگِ سازمانی: طلایی `#CD9E53` و سورمه‌ای `#032340` (در بسیاری فایل‌ها به‌صورت `const GOLD`/`const NAVY` هاردکد شده‌اند).
- **مسیریابی:** React Router DOM v7 (`createBrowserRouter`). `RootLayout` همه‌ی صفحات را با Header/Footer و موتورِ اسکرول می‌پیچد.
- **انیمیشن و اسکرول:**
- **GSAP + ScrollTrigger:** انیمیشن‌های مبتنی بر اسکرول.
- **Lenis:** اسکرولِ نرم هماهنگ با تیکرِ GSAP — **فقط دسکتاپ** (روی لمسی به مومنتومِ بومیِ سیستم‌عامل واگذار می‌شود تا لگ نشود).
- **Framer Motion:** میکروانیمیشن‌ها، پاپ‌آپ‌ها و ترنزیشن‌ها.
- **سه‌بعدی و نقشه:** Three.js + React Three Fiber، `three-globe` و `react-globe.gl` برای کره‌ی زمینِ تعاملی.
- **نمودار:** ApexCharts (صفحه‌ی Market).
- **مدیریت وضعیت:** صرفاً **React Context** (زبان و احراز هویت). بدون کتابخانه‌ی state خارجی.
### قابلیت‌های کلیدی
1. **دوزبانه/RTL:** هوک `useLang()` (`src/context/LangContext`) مقدار `{ lang, toggle }` می‌دهد؛ کامپوننت‌ها دیکشنریِ درون‌خطیِ `{ fa, en }` دارند و جهتِ صفحه با `dir` تنظیم می‌شود.
2. **اعدادِ فارسی:** یک «بومی‌سازِ ارقام» در `RootLayout` همه‌ی ارقامِ لاتینِ نمایش‌داده‌شده را در حالتِ فارسی به فارسی تبدیل می‌کند (با MutationObserver برای محتوای دیرلودشده).
3. **تاریخ شمسی:** بدون کتابخانه‌ی تاریخ — مستقیماً با `Intl.DateTimeFormat('fa-IR-u-ca-persian', …)`.
4. **PWA و موبایل:** manifest + service worker (نصب‌پذیری + کشِ آفلاین)؛ صفحه روی موبایل **غیرقابلِ زوم** است (viewport + بلوکِ pinch/double-tap برای iOS).
5. **جستجوی سراسری:** آیکونِ سرچِ هدر → صفحه‌ی `/search` که به‌صورت کلاینت‌ساید روی همه‌ی محتوا (گزارش‌ها، مطالب، «در یک نگاه»، رادار آینده، ویدیوکست/پادکست، رویدادها) می‌گردد و به صفحه‌ی جزئیاتِ هر مورد لینک می‌دهد.
### دستورات (در پوشه‌ی `frontend/`)
```bash
cd frontend
npm install
npm run dev # سرورِ توسعه‌ی Vite (HMR)
npx tsc -b --noEmit # فقط type-check (سریع‌ترین حلقه‌ی اعتبارسنجی)
npm run lint # ESLint
npm run build # tsc -b && vite build → خروجی در dist/
npm run preview # پیش‌نمایشِ بیلدِ پروداکشن
```
برای دیدنِ دادهٔ واقعیِ پنل در حالتِ توسعه:
```bash
VITE_PANEL_API=https://cms-steelforesight.liara.run npm run dev
```
> هیچ فریم‌ورکِ تستی پیکربندی نشده؛ «تأیید» یعنی `tsc` تمیز + بازدیدِ سرورِ در حالِ اجرا.
---
## ۳. پنل مدیریت و بک‌اند (`panel/`)
سرورِ Express که هم API می‌دهد و هم رابطِ مدیریت (CMS) را سرو می‌کند.
### پشته‌ی فناوری
- **سرور:** Express 4 روی Node.js.
- **پایگاه داده:** PostgreSQL (لیارا) با ماژول `pg` (Pool روی `DATABASE_URL`). در `db.js` یک facadeِ شبیهِ `better-sqlite3` ساخته شده: `db.prepare(sql).get/all/run(...)`**همه async و باید await شوند**. جداول و ایندکس‌ها در زمانِ استارت‌آپ به‌صورت idempotent ساخته/مهاجرت می‌شوند.
- **امنیت/احراز هویت:** `bcryptjs` (هشِ گذرواژه)، `jsonwebtoken` (کوکیِ HttpOnly با `Secure`/`SameSite` پشتِ TLS)، `helmet` (هدر/CSP)، `express-rate-limit` (محدودسازیِ ورود و فرمِ تماس). CORS با `ALLOWED_ORIGINS` کنترل می‌شود (و در توسعه هر `localhost`).
- **آپلود و تصویر:** `multer` (بافرِ حافظه) + `sharp` (چرخشِ EXIF، ریسایز تا ۲۰۰۰px و خروجیِ **WebP**). `pdf-parse` برای استخراجِ متنِ PDF.
- **ذخیره‌سازی:** **S3-compatible** (object storage لیارا) در صورتِ تنظیمِ متغیرها؛ وگرنه fallback به دیسکِ محلی `panel/uploads/`.
- **هوش مصنوعی:** SDKهای **OpenAI** و **Anthropic (Claude)** برای خلاصه‌سازی و استخراجِ دادهٔ کلیدی از اسناد.
- **رابطِ مدیریت:** SPA با **Vanilla JS** در `panel/public/` (بدون build). تب‌ها در دو گروه: **محتوا** (در یک نگاه، رادار آینده، ویدیوکست/پادکست، رویدادها، بنرها) و **کاربران** (کاربران سایت، خبرنامه).
### دستورات (در پوشه‌ی `panel/`)
```bash
cd panel
npm install
npm run seed # ساختِ ادمینِ اولیه از روی .env (ADMIN_USERNAME/PASSWORD)
npm start # node server.js → http://localhost:3001
npm run dev # node --watch server.js
```
---
## ۴. پایگاه داده
جداولِ اصلی (PostgreSQL):
| جدول | کاربرد |
| :--- | :--- |
| `users` | ادمین‌های پنل با نقشِ `admin` یا `owner` |
| `articles` | مقالات/گزارش‌ها (مدلِ منعطف؛ با `category`/`type` تفکیک می‌شود) |
| `radar_items` | آیتم‌های «در یک نگاه» در ۵ دسته: market/tech/commodity/geo/energy |
| `radar_pages` | صفحاتِ «رادار آینده» (مقاله‌ی بلوکیِ هر زیرمنو) |
| `risk_signals` | سیگنال‌های ریسک با سطوحِ critical…opportunity |
| `events` | رویدادهای تقویم |
| `team_members` | اعضای تیم/خبرگان |
| `market_prices`, `market_chart_points` | قیمت‌ها و نمودارهای صفحه‌ی Market (**دستی، ادیت‌شونده در پنل**) |
| `banners`, `integrations`, `institute_stats`, `vision_items`, `advisory_board`, `plans`, `factory_reports` | بخش‌های مختلفِ محتواییِ سایت |
| `members` | اعضای ثبت‌نامیِ سایت (موبایل/OTP) + `last_login`, `is_active` |
| `purchases` | خریدِ گزارش‌های غیررایگانِ اعضا |
| `member_activity` | لاگِ فعالیتِ اعضا (بازدیدِ صفحه + کلیک) |
| `subscribers` | ایمیل‌های عضویت در خبرنامه (فرمِ فوتر) |
> جدولِ `prices` (اسکرپرِ قدیمیِ tgju) دیگر استفاده نمی‌شود؛ اسکرپرِ زنده حذف شده و صفحه‌ی Market از `market_prices` می‌خواند.
---
## ۵. احراز هویت و اعضا
دو نشستِ مجزا:
- **ادمینِ پنل:** کوکیِ `session` (جدولِ `users`). نقشِ `owner` می‌تواند ادمین‌ها و اعضا را حذف کند.
- **عضوِ سایت:** کوکیِ `member_session` (جدولِ `members`).
**ورود/ثبت‌نامِ اعضا با موبایل + کدِ یک‌بارمصرف (OTP):** ارسالِ پیامک با **کاوه‌نگار** (`KAVENEGAR_API_KEY`). در نبودِ کلید (محیطِ لوکال) کد در کنسولِ سرور چاپ می‌شود تا تست ممکن باشد. بازنشانیِ رمز هم از طریقِ SMS ممکن است.
**مدیریتِ کاربران در پنل** (تب «کاربران سایت»): فهرستِ اعضا با شماره و **آخرین ورود**، صفحه‌ی جزئیات (خریدها + **تایم‌لاینِ فعالیت: بازدید/کلیک****مسدودسازی/رفعِ مسدودی** (`is_active`) و **حذف**. عضوِ مسدودشده در سمتِ سایت هم اثر می‌گیرد: `AuthContext` نشست را هنگامِ لود و بازگشتِ فوکوسِ تب با `/api/members/me` اعتبارسنجی می‌کند و در صورتِ `403` کاربر را خارج می‌کند.
---
## ۶. اتصال فرانت‌اند به پنل (Wiring)
فرانت‌اند هنگامِ استارت‌آپ، محتوای چند بخش را از پنل واکشی می‌کند (در `frontend/src/main.tsx` توابعِ `bootstrap*` فراخوانی می‌شوند) و در صورتِ در دسترس نبودنِ پنل به دادهٔ ایستای داخلِ `src/content` و `src/data` به‌عنوان fallback برمی‌گردد. نمونه‌ها: `/api/articles` (گزارش‌ها)، `/api/radar` (در یک نگاه)، `/api/events`، `/api/market-prices` و غیره. احراز هویتِ اعضا از طریقِ `AuthContext` و مسیرهای `/api/members/*` انجام می‌شود.
آدرسِ پنل از متغیرِ `VITE_PANEL_API` خوانده می‌شود (در پروداکشن هنگامِ build در Dockerfile مقدارِ `https://cms-steelforesight.liara.run` به باندل تزریق می‌شود).
---
## ۷. فهرست APIها
خواندنی‌ها عمومی‌اند؛ نوشتنی‌ها (POST/PUT/PATCH/DELETE) نیازمندِ کوکیِ نشست یا هدرِ `Authorization: Bearer <token>` هستند.
| متد | مسیر | احراز هویت | توضیح |
| :--- | :--- | :--- | :--- |
| POST | `/api/auth/login` `/logout` | — / — | ورود/خروجِ ادمین |
| GET | `/api/auth/me` | ادمین | مشخصاتِ ادمینِ جاری |
| GET/POST/PUT/DELETE | `/api/articles[...]` | خواندن آزاد / نوشتن ادمین | CRUD مقالات |
| GET/POST/PUT/DELETE | `/api/radar`, `/api/radar-pages`, `/api/events`, `/api/banners`, `/api/risks`, `/api/team`, `/api/market-prices` … | خواندن آزاد / نوشتن ادمین | CRUD بخش‌های محتوایی |
| POST | `/api/uploads`, `/api/uploads/raw` | ادمین | آپلودِ تصویر (→WebP) / ویدیو و PDF (→S3) |
| POST | `/api/admin/import` | ادمین | ایمپورتِ دادهٔ تحلیلیِ هوش مصنوعی |
| POST | `/api/members/otp/send` `/otp/verify` | — | ورود/ثبت‌نام با OTP |
| POST | `/api/members/register-verify` | — | تکمیلِ ثبت‌نام پس از تأییدِ کد |
| GET/PUT | `/api/members/me` | عضو | پروفایلِ عضو |
| GET | `/api/members/me/purchases[...]` | عضو | خریدها و دانلودِ گزارش |
| POST | `/api/members/activity` | عضو | ثبتِ فعالیت (بازدید/کلیک) |
| GET | `/api/members` `/api/members/:id` `/:id/activity` | ادمین | فهرست/جزئیات/فعالیتِ اعضا |
| PATCH/DELETE | `/api/members/:id` | ادمین/owner | مسدودسازی/حذفِ عضو |
| POST/GET/DELETE | `/api/newsletter[...]` | نوشتن آزاد / خواندن ادمین | عضویت در خبرنامه و مدیریتِ آن |
| POST | `/api/contact` | — | فرمِ تماس با ما |
| GET | `/api/health` | — | سلامتِ سرور |
---
## ۸. استقرار (Deployment)
هر دو اپ روی **لیارا (Liara)** مستقر می‌شوند (دو اپِ جدا).
### فرانت‌اند — اپِ `steelforesight`
خروجیِ استاتیک، با Dockerfileِ دو‌مرحله‌ای: مرحله‌ی Node برای `vite build` و سپس Nginxِ سبک برای سروِ `dist/` روی پورتِ **۷۸۶۰** (سازگار با Hugging Face Spaces).
```bash
cd frontend
liara deploy --app steelforesight --platform docker --port 7860 --build-location iran
```
`VITE_PANEL_API` هنگامِ build از طریقِ `ARG` در Dockerfile تزریق می‌شود.
### پنل — اپِ `cms-steelforesight`
```bash
cd panel
liara deploy --app cms-steelforesight --platform node --build-location iran
```
متغیرهای محیطیِ لازم (در کنترل‌پنلِ هاست):
- `DATABASE_URL` — اتصالِ PostgreSQL.
- `JWT_SECRET` — رشته‌ی تصادفیِ بلند (≥۳۲ کاراکتر).
- `ADMIN_USERNAME` / `ADMIN_PASSWORD` — برای `npm run seed`.
- `ALLOWED_ORIGINS` — دامنه‌ی فرانت برای عبور از CORS.
- `KAVENEGAR_API_KEY` — ارسالِ پیامکِ OTP.
- اختیاری: متغیرهای ایمیل و object storage (`LIARA_ENDPOINT`, `LIARA_BUCKET`, `LIARA_ACCESS_KEY`, `LIARA_SECRET_KEY`).