# راهنمای جامع پروژه اندیشکده فولاد آینده (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`).
