وباپلیکیشنی برای مدیریت تمرین بدنسازی، با رابط کاربری کاملاً فارسی و راستبهچپ (RTL)؛ شامل برنامهساز خودکار تمرین، بانک حرکات جستوجوپذیر و پیگیری پیشرفت با نمودار.
| لایه | فناوری |
|---|---|
| فرانتاند | React 18، Vite، React Router، TanStack Query، React Hook Form، Recharts، Tailwind CSS v4 |
| بکاند | Node.js، Express 4، Mongoose |
| پایگاهداده | MongoDB (میزبانیشدهٔ اختصاصی) |
| احراز هویت | JWT (Authorization: Bearer <token>)، bcrypt |
سراسر پروژه با جاوااسکریپت خالص نوشته شده و از TypeScript استفاده نمیکند.
این سند در پنج بخش سازماندهی شده است:
- معماری سیستم
- ساختار پایگاهداده
- مستندات API
- فایلهای طراحی UI/UX و نسخهٔ پیادهسازیشده
- دستورالعمل نصب و راهاندازی سرور و محیط ابری
پروژه یک مونوریپو (monorepo) با دو اپلیکیشن مستقل است که با npm workspaces مدیریت میشود:
مرورگر ──HTTP──▶ سرور توسعهٔ Vite (پورت 5173) ──proxy /api──▶ Express (پورت 5000) ──▶ MongoDB (پورت 27017)
│ (سرو React) REST JSON Mongoose
└── localStorage: توکن JWT
- کلاینت (client) یک اپلیکیشن تکصفحهای (SPA) مبتنی بر React است. هرگز مستقیم به پایگاهداده دسترسی ندارد و فقط از طریق API با سرور ارتباط برقرار میکند.
- سرور (server) یک REST API بدون حالت (stateless) است. تمام اعتبارسنجی، احراز هویت و دسترسی به پایگاهداده منحصراً روی سرور انجام میشود.
- وضعیت برنامه در دو جا نگهداری میشود: توکن JWT در
localStorageمرورگر (برای شناسایی کاربر) و MongoDB (برای همهٔ دادههای دیگر).
دلیل اهمیت این جداسازی این است که سرور تنها بخشی از سیستم است که به هیچ ورودی از سمت کلاینت اعتماد نمیکند؛ چون کلاینت را هرکسی میتواند تغییر دهد. هش کردن رمز عبور، اعتبارسنجی ورودی و محدودسازی مالکیت داده، همگی فقط در سرور پیادهسازی شدهاند.
bodybuilding/
├── client/ فرانتاند React
│ └── src/
│ ├── api/ نمونهٔ axios بههمراه یک ماژول برای هر منبع داده
│ ├── components/ کامپوننتهای چیدمان، رابط کاربری مشترک، نمودارها
│ ├── context/ AuthContext — نگهداری توکن و اعتبارسنجی نشست
│ ├── pages/ یک کامپوننت بهازای هر مسیر (route)
│ ├── constants/ برچسبهای فارسی برای مقادیر enum سمت سرور
│ └── utils/ تاریخ جلالی، اعداد فارسی، جاسازی ویدیو
└── server/ API با Express
└── src/
├── models/ مدلهای User، Exercise، WorkoutProgram، ProgressLog
├── controllers/ هندلرهای درخواست (منطق تجاری)
├── routes/ تعریف مسیرها بههمراه قوانین express-validator
├── services/ منطق تولید برنامهٔ تمرینی
├── middleware/ احراز هویت، اعتبارسنجی، مدیریت خطا
└── seed/ دادهٔ اولیهٔ بانک حرکات
ترتیب اجرای میانافزارها اهمیت دارد؛ هر لایه به لایههای پیش از خودش وابسته است:
helmet()— افزودن هدرهای امنیتی به هر پاسخcors()— مجاز کردن origin مرورگرexpress.json()— پردازش بدنهٔ درخواستexpress-mongo-sanitize()— حذف عملگرهای$از ورودی، بلافاصله بعد از پارس شدن و پیش از رسیدن به هر هندلرmorgan()— لاگگیری (فقط در محیط توسعه)- مسیرهای
/api/health،/api/auth،/api/exercises،/api/programs،/api/progress notFound— بازگرداندن کد ۴۰۴ برای مسیرهای نامشخصerrorHandler— تبدیل هر خطا به یک پاسخ JSON یکدست
برای جزئیات کاملتر معماری، جریان گامبهگام درخواستها و سیستم طراحی، به فایل ARCHITECTURE.md مراجعه کنید.
پایگاهداده از نوع MongoDB (سندمحور و بدون نیاز به شِمای رابطهای ثابت) است و در سمت سرور با Mongoose مدلسازی میشود. به همین دلیل، فایل SQL یا دیاگرام رابطهای (ER) جداگانهای در پروژه وجود ندارد؛ ساختار داده مستقیماً در فایلهای زیر تعریف شده است:
| مدل | فایل | توضیح |
|---|---|---|
| کاربر (User) | server/src/models/User.js | حساب کاربری، رمز عبور هششده، پروفایل تمرینی |
| حرکت (Exercise) | server/src/models/Exercise.js | بانک حرکات؛ دادهٔ مرجع مشترک بین همهٔ کاربران |
| برنامهٔ تمرینی (WorkoutProgram) | server/src/models/WorkoutProgram.js | برنامهٔ هفتگی هر کاربر |
| لاگ پیشرفت (ProgressLog) | server/src/models/ProgressLog.js | ثبت وزنه، تکرار و مدتزمان هر ست تمرینی |
User
- فیلدهای
name،email(یکتا)، وpassword(هششده با bcrypt؛ باselect: falseتا در پاسخهای عادی API بازگردانده نشود) role: نقش کاربر، با مقدار پیشفرضuserprofile: جنسیت، سال تولد، قد، وزن، سطح تمرینی و هدف
رمز عبور در یک هوک pre('save') بهطور خودکار هش میشود؛ در نتیجه هیچ کنترلری امکان ذخیرهٔ رمز عبور بهصورت متن ساده را ندارد، حتی در کدهای آینده.
Exercise
- فیلدهای
name(فارسی)،nameEn،descriptionوvideoUrl muscleGroup،equipmentوdifficulty: هرکدام محدود به مقادیر ثابتی که درserver/src/constants/enums.jsتعریف شدهاند- یک ایندکس ترکیبی روی
{ muscleGroup, equipment, difficulty }برای جستوجوی سریعتر
WorkoutProgram
- ارجاع (reference) به
user، یعنی مالک برنامه days: آرایهای از روزهای تمرین که بهصورت جاسازیشده (embedded) ذخیره میشوند- هر روز شامل آرایهای از حرکات است؛ هر حرکت با یک
ObjectIdبه سندExerciseارجاع داده میشود، در حالیکه مقادیرsets،repsوrestSecondsمخصوص همان برنامه هستند isActive: در هر لحظه فقط یک برنامه برای هر کاربر فعال است؛ تولید برنامهٔ جدید، برنامهٔ قبلی را غیرفعال میکند نه حذف — تا تاریخچه حفظ شود
ProgressLog
- ارجاع به
userوexercise sets: آرایهای از ستهای ثبتشده، شاملweightKg،repsوdurationSeconds- ایندکس ترکیبی روی
{ user, exercise, date }که مستقیماً به کوئریهای نمودار پیشرفت سرعت میبخشد
نکته: تاریخها همیشه در پایگاهداده بهصورت میلادی (ISO) و اعداد همیشه بهصورت لاتین ذخیره میشوند. تبدیل به تاریخ جلالی و اعداد فارسی فقط در لایهٔ نمایش، در فایل
client/src/utils/format.js، انجام میشود؛ همین موضوع باعث میشود مرتبسازی و کوئریهای بازهای تاریخ همیشه درست کار کنند.
مسیر پایهٔ همهٔ درخواستها /api است. مسیرهای محافظتشده به هدر Authorization: Bearer <token> نیاز دارند.
| متد | مسیر | نیاز به توکن | بدنه / پارامتر |
|---|---|---|---|
| POST | /auth/register | – | { name, email, password } ← { user, token } |
| POST | /auth/login | – | { email, password } ← { user, token } |
| GET | /auth/me | ✓ | اطلاعات کاربر جاری |
| PUT | /auth/me | ✓ | { name?, profile? } |
| PUT | /auth/change-password | ✓ | { currentPassword, newPassword } |
| متد | مسیر | نیاز به توکن | بدنه / پارامتر |
|---|---|---|---|
| GET | /exercises | – | ?search=&muscleGroup=&equipment=&difficulty=&page=&limit= |
| GET | /exercises/:id | – | یک حرکت مشخص |
| متد | مسیر | نیاز به توکن | بدنه / پارامتر |
|---|---|---|---|
| POST | /programs/generate | ✓ | { level, goal, daysPerWeek } — ساخت و فعالسازی خودکار برنامه |
| POST | /programs | ✓ | { title?, level, goal, daysPerWeek } — برنامهٔ خالی برای تکمیل دستی |
| GET | /programs | ✓ | همهٔ برنامههای کاربر |
| GET | /programs/active | ✓ | برنامهٔ فعال، یا null |
| GET | /programs/:id | ✓ | یک برنامهٔ مشخص |
| PUT | /programs/:id | ✓ | { title?, description?, level?, goal?, days? } |
| PUT | /programs/:id/activate | ✓ | فعالسازی این برنامه |
| DELETE | /programs/:id | ✓ | حذف برنامه |
| متد | مسیر | نیاز به توکن | بدنه / پارامتر |
|---|---|---|---|
| POST | /progress | ✓ | { exercise, date?, sets[], notes? } |
| GET | /progress | ✓ | ?exercise=&from=&to=&page=&limit= |
| GET | /progress/stats | ✓ | ?exercise=&from=&to= ← [{ date, maxWeight, totalReps, totalSets, totalDurationSeconds, volume }] |
| GET | /progress/exercises | ✓ | حرکاتی که کاربر برایشان لاگ ثبت کرده (برای انتخابگر نمودار) |
| GET | /progress/:id | ✓ | یک رکورد مشخص |
| PUT | /progress/:id | ✓ | ویرایش یک رکورد |
| DELETE | /progress/:id | ✓ | حذف یک رکورد |
خطاها به شکل { message, errors?: [{ field, message }] } بازگردانده میشوند. برای رکوردهایی که متعلق به کاربر دیگری هستند، پاسخ 404 بازگردانده میشود، نه 403؛ به این ترتیب وجود یا عدموجود رکورد برای کاربر دیگر فاش نمیشود.
نکته: مستندات تعاملی بهشکل OpenAPI یا Swagger هنوز برای پروژه تولید نشده و در فهرست کارهای آتی قرار دارد.
این پروژه فاقد فایل طراحی مجزا (مانند Figma یا Sketch) است؛ سیستم طراحی مستقیماً در کد پیادهسازی شده و همان کد، منبع حقیقت واحد (single source of truth) طراحی بهشمار میرود.
تعریفشده در فایل client/src/index.css بهصورت متغیرهای سراسری CSS:
- رنگ: سه طیف رنگی —
ink(خنثی؛ برای متن و سطوح)،flame(اصلی؛ برای دکمهها و حالت فعال) وvolt(تأکیدی؛ برای پیشرفت و پیام موفقیت) - کنتراست: تمام رنگهای متن در برابر پسزمینه، مطابق استاندارد WCAG AA (حداقل نسبت ۴.۵ به ۱) بررسی و تأیید شدهاند
- راستبهچپ (RTL): با سه مکانیزم پیادهسازی شده است — ویژگی
dir="rtl"روی تگ<html>، استفاده از خواص منطقی CSS (مانندps-*،me-*،text-start) بهجای خواص جهتی ثابت، و کلاسهایrtl:برای موارد استثنا مثل فلش برگشت - نمودارها: بهطور عمدی درون یک ظرف (container) با
dir="ltr"رندر میشوند، چون نمودارهای زمانی در همهٔ زبانها بهطور متعارف از چپ به راست خوانده میشوند - انیمیشن: بین ۱۵۰ تا ۳۰۰ میلیثانیه، فقط روی transform و opacity، و با پشتیبانی کامل از تنظیمات
prefers-reduced-motion - آیکونها: یک مجموعهٔ واحد و درونخطی (inline SVG) با حدود ۳۵ آیکون؛ بدون استفاده از هیچ ایموجی، چون ایموجی در پلتفرمهای مختلف ظاهر متفاوتی دارد
| بخش | مسیر |
|---|---|
| توکنهای طراحی (رنگ، سایه، انیمیشن) | client/src/index.css |
| مجموعهٔ آیکونها | client/src/components/Icon.jsx |
| کامپوننتهای پایهٔ مشترک (دکمه، ورودی، کارت و…) | client/src/components/common/index.jsx |
| چیدمان صفحات ورود و ثبتنام | client/src/components/layout/AuthLayout.jsx |
| چیدمان صفحات داخل برنامه | client/src/components/layout/AppLayout.jsx |
| نمودارهای پیشرفت | client/src/components/charts/ProgressCharts.jsx |
| ورودی تاریخ جلالی | client/src/components/JalaliDateInput.jsx |
هر صفحه یک کامپوننت مستقل در پوشهٔ client/src/pages/ است:
| صفحه | فایل |
|---|---|
| ورود | LoginPage.jsx |
| ثبتنام | RegisterPage.jsx |
| خانه | HomePage.jsx |
| داشبورد | DashboardPage.jsx |
| بانک حرکات | ExercisesListPage.jsx |
| جزئیات حرکت | ExerciseDetailPage.jsx |
| برنامهساز خودکار | ProgramGeneratorPage.jsx |
| ویرایش دستی برنامه | ProgramBuilderPage.jsx |
| نمایش برنامه | ProgramViewPage.jsx |
| ثبت پیشرفت | ProgressLogPage.jsx |
| نمودار پیشرفت | ProgressChartsPage.jsx |
| پروفایل کاربر | ProfilePage.jsx |
| صفحهٔ خطای ۴۰۴ | NotFoundPage.jsx |
برای مشاهدهٔ نسخهٔ زندهٔ رابط کاربری، پروژه را طبق بخش ۵ اجرا کنید و آدرس http://localhost:5173 را در مرورگر باز کنید.
- Node.js نسخهٔ ۱۸ به بالا
- MongoDB (نصب محلی یا سرویس ابری)
۱. نصب وابستگیها (یک دستور، هر دو workspace را نصب میکند):
npm install۲. نصب MongoDB Community Server
نصبکنندهٔ ویندوز را دانلود و اجرا کنید و گزینهٔ «Install MongoDB as a Service» را انتخاب کنید تا سرویس همراه با ویندوز بهطور خودکار اجرا شود. پورت پیشفرض 27017 است.
نکته برای کاربران ایران: آدرس CDN اصلی MongoDB، یعنی
fastdl.mongodb.org، از آیپیهای ایران خطای403 Forbiddenبازمیگرداند و همین موضوع باعث شکست دستورwinget install MongoDB.Serverنیز میشود. آدرس مبدأdownloads.mongodb.orgهمان فایل رسمی را سرو میکند و در دسترس است:curl.exe-L -o mongodb.msi https://downloads.mongodb.org/windows/mongodb-windows-x86_64-8.3.8-signed.msi (Get-FileHash mongodb.msi -Algorithm SHA256).Hashهش دریافتی را با چکسام منتشرشده در همان آدرس (با پسوند
.sha256) مقایسه کنید.استفاده از MongoDB Atlas از ایران ممکن نیست، چون این سرویس در آمریکا میزبانی میشود و مشمول تحریم است؛ حسابهای ساختهشده از آیپی ایران مسدود یا بسته میشوند. راهحل، میزبانی نسخهٔ متنباز خودِ MongoDB است، همانطور که در بالا توضیح داده شد. برای استقرار روی سرور، ارائهدهندههای ایرانی مانند لیارا (Liara) یا آروانکلاود (ArvanCloud) سرویس MongoDB مدیریتشده و میزبانی وب ارائه میدهند.
بررسی اجرا بودن سرویس:
Get-Service MongoDB۳. تنظیم سرور
فایل server/.env.example را به server/.env کپی و مقداردهی کنید:
PORT=5000
NODE_ENV=development
MONGO_URI=mongodb://127.0.0.1:27017/bodybuilding
JWT_SECRET=<یک رشتهٔ تصادفی و طولانی>
JWT_EXPIRES_IN=7d
CLIENT_ORIGIN=http://localhost:5173
بخش /bodybuilding در انتهای آدرس، نام پایگاهداده است و در اولین نوشتن بهطور خودکار ساخته میشود؛ نیازی به آمادهسازی دستی نیست. برای تولید یک JWT_SECRET قوی:
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"کلاینت برای توسعهٔ محلی به هیچ تنظیماتی نیاز ندارد — Vite مسیرهای /api را بهطور خودکار به پورت ۵۰۰۰ پروکسی میکند. فایل client/.env.example نیز برای زمانی که دو نیمهٔ پروژه روی دو origin جداگانه مستقر شوند، آماده شده است.
۴. بارگذاری بانک حرکات اولیه
npm run seedاین دستور ۲۰ حرکت را وارد پایگاهداده میکند و فقط مجموعهٔ exercises را دستکاری میکند؛ کاربران، برنامهها و لاگهای پیشرفت هرگز تغییر نمیکنند، بنابراین اجرای دوبارهٔ آن کاملاً بیخطر است.
۵. اجرای همزمان کلاینت و سرور
npm run dev- فرانتاند:
http://localhost:5173 - API:
http://localhost:5000
| دستور | کاربرد |
|---|---|
npm run dev | اجرای همزمان API و فرانتاند |
npm run dev:server | فقط اجرای API (با nodemon) |
npm run dev:client | فقط اجرای فرانتاند |
npm run seed | بازسازی بانک حرکات |
npm run build | ساخت نسخهٔ نهایی فرانتاند در پوشهٔ client/dist |
پروژه شامل فایلهای آمادهٔ Docker است:
| فایل | کاربرد |
|---|---|
Dockerfile | ساخت یک ایمیج واحد شامل کلاینت و سرور |
docker-compose.yml | اجرای محیط توسعه (کلاینت، سرور، MongoDB) |
docker-compose.prod.yml | اجرای محیط عملیاتی (اپلیکیشن، MongoDB، Nginx) |
nginx.conf | تنظیمات reverse proxy و گواهی SSL |
اجرای محلی برای آزمایش پیش از استقرار:
docker-compose up -d
docker-compose logs -fتوقف سرویسها:
docker-compose downمراحل کامل استقرار روی سرور — شامل نصب Docker، آپلود پروژه، تنظیم متغیرهای محیطی و اجرای نسخهٔ عملیاتی — در فایل DOCKER_DEPLOYMENT.md شرح داده شده است. راهنمای اختصاصی استقرار روی میزبانهای ایرانی نیز در فایل DEPLOY_IRAN.md آمده، و برای یک شروع سریعتر با Docker میتوانید فایل QUICKSTART_DOCKER.md را ببینید.
این موارد بهطور آگاهانه از ساخت اولیه کنار گذاشته شدهاند و فاز طبیعی بعدی پروژه بهشمار میروند:
- پنل مدیریت برای مدیریت حرکات و کاربران (فیلد
roleاز پیش در مدلUserوجود دارد) - اعلانهای ایمیل یا پیامک و یادآوری جلسات تمرینی
- مستندات تعاملی OpenAPI / Swagger
- تستهای خودکار واحد و یکپارچگی
- پایپلاین CI/CD و پیکربندی استقرار خودکار