ایمن پیشگامان — مونوریپو (سایت + API + پنل مدیریت)
سایت ایمن پیشگامان بههمراه بکند و پنل مدیریت محتوا. همهی متنها، تصاویر، دستهها و محصولات سایت از پنل مدیریت قابل ویرایشاند.
| بخش | مسیر | فناوری |
|---|---|---|
| سایت | apps/web |
Nuxt 4 (SSR + کش SWR)، Vue 3، Tailwind v4، Ant Design Vue، Pinia |
| API | apps/api |
NestJS 12، Prisma 7، PostgreSQL، ذخیرهساز S3 (MinIO) |
| پنل مدیریت | apps/admin |
Vue 3 + Vite، Ant Design Vue، Tailwind v4، Pinia، Vue Router |
| کد مشترک | packages/shared |
اسکیماهای Zod و تایپها (مشترک بین هر سه اپ) |
ابزار مونوریپو: pnpm workspaces + Turborepo.
مرورگر ──► gateway (nginx)
├─ imenpishgaman.ir → web (Nuxt SSR، صفحات کششده)
├─ admin.imenpishgaman.ir → admin (فایلهای استاتیک)
├─ /api/* → api (NestJS) ──► PostgreSQL
└─ /media/* → MinIO (تصاویر آپلودشده)
ذخیره در پنل ──► API ──► POST web:/_internal/revalidate ──► کش صفحات سایت پاک میشود
ساختار پوشهها
apps/
web/ سایت (همان طراحی قبلی؛ دادهها از API)
app/stores/site.ts محتوای سایت از GET /api/public/site (یک بار در هر رندر)
app/plugins/api.ts $api — در SSR آدرس داخلی API، در مرورگر /api
server/routes/ sitemap.xml (از دیتابیس)، robots.txt، manifest، _internal/revalidate
api/
prisma/schema.prisma مدل داده؛ migrations/ کنار آن
src/ ماژولها: auth, users, catalog, media, sections, contact, public, dashboard
src/seed/ مقداردهی اولیه (محتوای فعلی سایت + ۸ دسته / ۸۹ محصول)
seed-assets/ تصاویر اولیه که seed در MinIO آپلود میکند
test/ تستهای e2e
admin/
src/pages/ داشبورد، محصولات، دستهها، بخشهای سایت، پیامها، رسانه، کاربران
src/sections/ فرم اختصاصی هر بخش سایت
packages/shared/src/ sections.ts (اسکیمای بخشها)، catalog.ts، admin.ts، icons.ts
docker/ Dockerfile هر اپ و پیکربندی nginx
docker-compose.yml استقرار production
docker-compose.dev.yml PostgreSQL + MinIO برای توسعه
راهاندازی محیط توسعه
پیشنیاز: Node.js 22.19 یا جدیدتر (۲۴ توصیه میشود)، Docker.
corepack enable pnpm # در ویندوز بدون دسترسی ادمین:
# corepack enable pnpm --install-directory "%APPDATA%\npm"
pnpm install
pnpm infra:up # PostgreSQL روی 5433 و MinIO روی 9000 (کنسول: 9001)
cp apps/api/.env.example apps/api/.env
cp apps/web/.env.example apps/web/.env
pnpm db:migrate # ساخت جدولها
pnpm db:seed # محتوای اولیه + کاربر مدیر (ADMIN_PHONE / ADMIN_PASSWORD در apps/api/.env)
pnpm dev # هر سه اپ با هم
| آدرس | چیست |
|---|---|
| http://localhost:3000 | سایت |
| http://localhost:5173 | پنل مدیریت |
| http://localhost:4000/api | API |
| http://localhost:9001 | کنسول MinIO |
در توسعه، سرور Nuxt و Vite مسیرهای /api و /media را به API و MinIO پراکسی میکنند؛ در production همین کار را nginx انجام میدهد. به همین دلیل آدرس تصاویر همهجا بهصورت /media/... ذخیره میشود.
اسکریپتها (از ریشهی پروژه)
| دستور | کار |
|---|---|
pnpm dev |
اجرای همهی اپها در حالت توسعه |
pnpm build |
build همهی پکیجها |
pnpm typecheck |
بررسی TypeScript همهی پکیجها |
pnpm test |
تستهای e2e بکند (روی دیتابیس توسعه؛ دادههای تست پاک میشوند) |
pnpm db:migrate |
ساخت/اعمال migration (prisma migrate dev) |
pnpm db:seed |
مقداردهی اولیه؛ اجرای دوباره چیزی را بازنویسی نمیکند |
pnpm db:studio |
Prisma Studio برای دیدن دادهها |
pnpm infra:up / infra:down |
روشن/خاموش کردن PostgreSQL و MinIO |
برای برگرداندن متنهای سایت به محتوای اولیه: SEED_OVERWRITE_SECTIONS=1 pnpm db:seed.
پنل مدیریت
- محصولات: افزودن/ویرایش، تصویر اصلی و گالری، توضیحات کامل، جدول مشخصات فنی، ویژگیهای کلیدی، کاربردها، استانداردها، سایزها و مدلها، برند و کشور سازنده، بستهبندی و حداقل سفارش، سئو، انتشار یا پیشنویس، کپی، مرتبسازی (با فیلتر یک دسته). هر محصول صفحهی اختصاصی
/products/<اسلاگ>دارد (گالری با بزرگنمایی، مشخصات، محصولات مرتبط، دکمهی درخواست قیمت که فرم تماس را با نام محصول پر میکند، JSON-LD نوع Product). بخشهایی که پر نشدهاند در صفحه نمایش داده نمیشوند. - دستهبندیها: کاور، زیرگروهها (فیلترهای صفحهی دسته)، سئو، ترتیب نمایش.
- بخشهای سایت: Hero، نوار متحرک، آمار، معرفی محصولات، درباره ما، خدمات، استانداردها، صنایع، نظرات، تماس، فوتر و تنظیمات سایت (تلفن، ایمیل، نشانی، ساعات کاری، شبکههای اجتماعی، سئوی پیشفرض).
- پیامهای تماس: درخواستهای فرم مشاورهی سایت، با وضعیت جدید / خواندهشده / بایگانی.
- کتابخانه رسانه: همهی تصاویر بهصورت خودکار بهینه و به WebP تبدیل میشوند. تصویری که جایی استفاده شده قابل حذف نیست.
- کاربران و نقشها: «مدیر کل» به همهچیز دسترسی دارد. «ویرایشگر» بهجز کاربران و تنظیمات سایت، همهی بخشها را میبیند.
تغییرات پس از ذخیره، حداکثر ظرف چند ثانیه روی سایت دیده میشوند. اگر فراخوانی پاککردن کش به هر دلیلی نرسد، صفحهها در هر صورت هر ۶۰ ثانیه تازه میشوند.
امنیت ورود: access token کوتاهعمر (۱۵ دقیقه) فقط در حافظهی مرورگر نگه داشته میشود و refresh token در کوکی httpOnly است. refresh token در هر استفاده عوض میشود. اگر یک توکن باطلشده دوباره استفاده شود، همهی نشستهای آن کاربر بسته میشوند. رمزها با argon2 ذخیره میشوند و تعداد تلاش برای ورود و ارسال فرم تماس محدود است.
راهنمای توسعه
افزودن فیلد به یک بخش سایت (مثلاً یک متن جدید در Hero):
- اسکیمای آن بخش را در
packages/shared/src/sections.tsتغییر دهید. اگر فیلد اجباری است، مقدار پیشفرض بدهید (text())، وگرنه دادههای فعلی دیتابیس دیگر معتبر نیستند. - فیلد را به فرم همان بخش در
apps/admin/src/sections/اضافه کنید. - در کامپوننت سایت (
apps/web/app/components/sections/) از آن استفاده کنید. - مقدار اولیه را در
apps/api/src/seed/data/sections.tsاضافه کنید.
یک اسکیمای Zod هم ورودی API را اعتبارسنجی میکند و هم فرم پنل را. برای همین پیامهای خطا در هر دو یکسان و فارسیاند.
تغییر مدل دیتابیس: apps/api/prisma/schema.prisma را ویرایش کنید و pnpm db:migrate را اجرا کنید. اسم migration را میپرسد. فایل migration را هم commit کنید.
آیکونها: آیکونهای قابلانتخاب در پنل در packages/shared/src/icons.ts تعریف شدهاند. برای افزودن آیکون جدید، آن را به همین لیست، به apps/web/app/components/ui/DynamicIcon.vue و به apps/admin/src/components/icons.ts اضافه کنید. این تکرار عمدی است تا فقط همین آیکونها وارد باندل شوند.
Ant Design و Tailwind: استایلهای Tailwind v4 داخل cascade layer هستند و CSS-in-JS آنتدیزاین بیرون از layer. بنابراین روی کامپوننتهای antd کلاس ظاهری Tailwind نگذارید. در سایت، پالت رنگ در دو جا تعریف شده است: @theme در main.css و palette در app/design/theme.ts. هنگام تغییر، هر دو را همگام کنید.
استقرار (production)
cp .env.example .env # همهی رمزها و دامنهها را تنظیم کنید
docker compose up -d --build
docker compose exec api node dist/seed/seed.js # فقط بار اول
- کانتینر
gatewayروی پورتHTTP_PORT(پیشفرض 8080) گوش میدهد و هر دو دامنه (SITE_DOMAINوADMIN_DOMAIN) را سرو میکند. TLS را nginx یا Traefik روی سرور یا CDN جلوی آن تأمین میکند. هر دو دامنه باید به سرور اشاره کنند. - سرویس یکبارهی
migrateپیش ازapiاجرا میشود، migrationهای جدید را اعمال میکند و خارج میشود. Prisma CLI فقط در همین image هست و image اجرایی API سبک میماند. - نام پروژهی Compose ثابت و برابر
imenاست، تا باdocker-compose.dev.yml(PostgreSQL و MinIO توسعه) هیچ کانتینر یا volume مشترکی نداشته باشد. - سرویس
backupهر روز یک dump از دیتابیس در./backupsمیسازد و dumpهای قدیمیتر از ۱۴ روز را پاک میکند. بازگردانی:docker compose exec -T postgres pg_restore -U imen -d imen --clean < backups/imen-YYYY-MM-DD.dump - از فایلهای MinIO (volume
miniodata) هم جداگانه بکاپ بگیرید.
اگر سرور به رجیستری npm دسترسی ندارد، دو راه هست:
- در
.envمقدارNPM_REGISTRYرا روی یک mirror در دسترس بگذارید. - imageها را روی سیستم توسعه بسازید و به سرور منتقل کنید:
docker compose build docker save imen-api imen-migrate imen-web imen-admin | gzip > imen-images.tar.gz # روی سرور: gunzip -c imen-images.tar.gz | docker load && docker compose up -d
Object Storage ابرآروان (یا هر S3 دیگر) بهجای MinIO: در سرویس api، مقادیر S3_ENDPOINT، S3_BUCKET و کلیدها را تنظیم کنید و S3_ENSURE_BUCKET را false بگذارید. MEDIA_PUBLIC_URL را روی آدرس عمومی باکت یا CDN بگذارید. بعد از آن به سرویس minio و مسیر /media در gateway نیازی نیست.
کارهای باقیمانده و پیشنهادها
- پر کردن جزئیات محصولات (توضیحات کامل، مشخصات فنی، استانداردها و ...) از پنل؛ این فیلدها برای محصولات فعلی خالیاند و فعلاً صفحهی محصول توضیح دسته را نشان میدهد.
- عکس برای ۱۷ محصول پوشاک کار و تجهیزات ترافیک (فعلاً کاور دسته نمایش داده میشود).
- ایمپورت/اکسپورت اکسل محصولات برای ورود دستهجمعی.
- اعلان پیام تماس جدید با ایمیل، پیامک یا ربات بله/تلگرام.
- پوشهی
محصولات/(عکسها و فایلهای Word خام) و فایلهای_dev.logوlanding-nextjs-seo.skillبهتر است از ریپو خارج شوند. - لوگوی رسمی (
apps/web/public/images/logo.png)، تصویر اختصاصی Open Graph با ابعاد ۱۲۰۰×۶۳۰ و آیکونهای PNG برای PWA. - CI روی سرور git (
pnpm typecheck && pnpm build && pnpm test).