211 lines
16 KiB
Markdown
211 lines
16 KiB
Markdown
# راهنمای جامع پروژه اندیشکده فولاد آینده (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/`)
|
||
|
||
پورتالِ محتواییِ فارسیمحور (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`).
|