# 🏥 نوبت724 (Nobat724) - سیستم نوبت‌دهی آنلاین پزشکی ## 📋 فهرست مطالب - [معرفی پروژه](#معرفی-پروژه) - [معماری و تکنولوژی](#معماری-و-تکنولوژی) - [ساختار پروژه](#ساختار-پروژه) - [ویژگی‌های کلیدی](#ویژگیهای-کلیدی) - [راه‌اندازی پروژه](#راهاندازی-پروژه) - [سیستم Multi-Domain](#سیستم-multi-domain) - [احراز هویت و مجوزها](#احراز-هویت-و-مجوزها) - [مسیرها و صفحات](#مسیرها-و-صفحات) - [کامپوننت‌های اصلی](#کامپوننتهای-اصلی) - [API و سرویس‌ها](#api-و-سرویسها) - [Deployment](#deployment) --- ## 🎯 معرفی پروژه **نوبت724** یک پلتفرم جامع و پیشرفته برای نوبت‌دهی آنلاین پزشکی است که امکان رزرو نوبت از پزشکان و کلینیک‌ها را به صورت آنلاین فراهم می‌کند. ### ویژگی‌های اصلی: - ✅ **Multi-Domain Architecture**: پشتیبانی از دامنه‌های مختلف برای شهرهای مختلف - ✅ **رزرو نوبت آنلاین**: سیستم کامل رزرو نوبت با تقویم شمسی - ✅ **پنل مدیریتی**: پنل کامل برای نمایندگان و پزشکان - ✅ **احراز هویت**: سیستم ورود و احراز هویت با OTP - ✅ **پرداخت آنلاین**: سیستم پرداخت یکپارچه - ✅ **Responsive Design**: طراحی کاملاً واکنش‌گرا با Tailwind CSS - ✅ **Dark Mode**: پشتیبانی کامل از حالت تاریک - ✅ **SEO Optimized**: بهینه‌سازی کامل SEO با متادیتای داینامیک --- ## 🏗️ معماری و تکنولوژی ### Frontend Framework - **Next.js 14.2.20** (App Router) - **React 18** - **Server Components** و **Client Components** ### UI/UX - **Material-UI (MUI) v7**: کامپوننت‌های UI - **Tailwind CSS 3.4**: استایل‌دهی - **Emotion**: CSS-in-JS - **Dark Mode**: با `next-themes` - **Responsive Design**: Mobile-first approach ### State Management & Data Fetching - **React Context API**: مدیریت state سراسری - **Axios**: درخواست‌های HTTP - **Server-Side Rendering (SSR)** ### Authentication & Authorization - **CASL**: مدیریت دسترسی‌ها - **JWT Tokens**: احراز هویت - **Cookie-based Auth**: ذخیره توکن‌ها ### کتابخانه‌های تخصصی - **jalali-moment & moment-jalaali**: تبدیل تاریخ شمسی - **jalaali-react-date-picker**: Date Picker فارسی - **react-toastify**: نوتیفیکیشن‌ها - **html2canvas & jspdf**: تولید PDF - **qrcode.react**: تولید QR Code - **@maptiler/sdk**: نمایش نقشه ### Development Tools - **Docker & Docker Compose**: Containerization - **ESLint**: Code Quality - **Prettier**: Code Formatting --- ## 📁 ساختار پروژه ``` nobat724_front/ ├── app/ # Next.js App Directory │ ├── layout.js # Root Layout با Metadata داینامیک │ ├── page.js # صفحه اصلی │ ├── globals.css # استایل‌های سراسری │ ├── about-us/ # درباره ما │ ├── appointment/[doctorId]/ # صفحه رزرو نوبت (Dynamic Route) │ ├── blog/[slug]/ # صفحه جزئیات بلاگ │ ├── blogs/ # لیست بلاگ‌ها │ ├── clinic/[slug]/ # صفحه جزئیات کلینیک │ ├── clinics/ # لیست کلینیک‌ها │ ├── contact-us/ # تماس با ما │ ├── dashboard/ # داشبورد عمومی │ ├── doctor/[slug]/ # صفحه جزئیات پزشک │ ├── doctors/ # لیست پزشکان │ ├── login/ # ورود │ ├── login-verify/ # تایید OTP │ ├── panel/(layout)/ # پنل مدیریتی (Route Group) │ │ ├── dashboard/ # داشبورد پنل │ │ ├── user-account/ # حساب کاربری │ │ ├── add-doctor/ # افزودن پزشک │ │ └── turns/ # مدیریت نوبت‌ها │ ├── specialties/ # تخصص‌های پزشکی │ └── component/ # کامپوننت‌های مشترک App │ ├── components/ # کامپوننت‌های اصلی │ ├── home/ # کامپوننت‌های صفحه اصلی │ ├── appointment/ # کامپوننت‌های رزرو نوبت │ ├── doctor/ # کامپوننت‌های پزشک │ ├── doctors/ # کامپوننت‌های لیست پزشکان │ ├── clinic/ # کامپوننت‌های کلینیک │ ├── clinics/ # کامپوننت‌های لیست کلینیک‌ها │ ├── panel/ # کامپوننت‌های پنل │ ├── layout/ # Layout کامپوننت‌ها │ ├── layoutPanel/ # Layout پنل │ ├── register/ # ثبت‌نام و ورود │ └── icons/ # آیکون‌های سفارشی │ ├── lib/ # کتابخانه‌ها و Utilities │ ├── ability.js # تعریف دسترسی‌ها (CASL) │ ├── auth.js # احراز هویت │ ├── getStateInfo.js # دریافت اطلاعات استان/شهر (Server) │ ├── getStateInfoClient.js # دریافت اطلاعات استان/شهر (Client) │ ├── getCanonicalUrl.js # تولید Canonical URL │ └── req.js # Helper برای Fetch │ ├── services/ # سرویس‌های API │ ├── api.js # تنظیمات Axios │ ├── response.js # API Endpoints │ └── clinicApi.js # APIهای مربوط به کلینیک │ ├── context/ # React Context │ └── ProvinceProvider.js # Context استان/شهر │ ├── data/ # فایل‌های JSON استاتیک │ ├── city.json # اطلاعات شهرها (Multi-Domain) │ ├── state.json # اطلاعات استان‌ها │ ├── specialties.json # تخصص‌های پزشکی │ ├── doctors.json # Mock Data پزشکان │ └── clinics.json # Mock Data کلینیک‌ها │ ├── helper/ # توابع کمکی │ └── index.js # Utility Functions │ ├── utils/ # Utilities │ └── index.js # توابع کمکی (removeToken و...) │ ├── hooks/ # Custom Hooks │ └── useCanonicalUrl.js # Hook برای Canonical URL │ ├── mui/ # تنظیمات MUI │ └── index.js # Theme Configuration │ ├── public/ # فایل‌های استاتیک │ ├── assets/ # تصاویر و آیکون‌ها │ └── fonts/ # فونت‌ها │ ├── middleware.js # Next.js Middleware ├── next.config.js # تنظیمات Next.js ├── tailwind.config.js # تنظیمات Tailwind ├── docker-compose.yml # Docker Compose ├── dockerfile # Dockerfile └── package.json # Dependencies ``` --- ## ✨ ویژگی‌های کلیدی ### 1. Multi-Domain Architecture پروژه از **معماری Multi-Domain** پشتیبانی می‌کند که به هر شهر اجازه می‌دهد دامنه مستقل خود را داشته باشد: ```javascript // در data/city.json { "id": "600", "domain": "nobat724.com", // دامنه اصلی "site_name": "نوبت724", "title": "رزرو نوبت پزشکی", // ... } ``` **نحوه عملکرد:** - در `lib/getStateInfo.js`: بررسی subdomain و تطبیق با شهر - در `app/layout.js`: تولید Metadata داینامیک بر اساس شهر - در `context/ProvinceProvider.js`: مدیریت Context شهر/استان ### 2. سیستم احراز هویت ```javascript // lib/auth.js - دریافت اطلاعات کاربر از Cookie export async function getUser() { const cookieStore = cookies(); const raw = cookieStore.get("access_token") && cookieStore.get("refresh_token") && cookieStore.get("uuid") && cookieStore.get("userInfo"); return raw ? raw : null; } // lib/ability.js - تعریف دسترسی‌ها export function defineAbilitiesFor(user) { if (user) { can("access", "Dashboard"); const parsedData = JSON.parse(user.value); if (parsedData.roles.find((item) => item === "representation")) { can("access", "Panel"); } } else { can("access", "Login"); } } ``` ### 3. سیستم رزرو نوبت فرآیند رزرو نوبت شامل مراحل زیر است: 1. **انتخاب تاریخ و زمان** (`components/appointment/date/`) 2. **ورود یا ثبت‌نام** (در صورت نیاز) 3. **وارد کردن اطلاعات بیمار** (`components/appointment/detail/`) 4. **پرداخت** (`components/appointment/paying/`) 5. **تایید نهایی** (`components/appointment/successPay/`) ### 4. پنل مدیریتی پنل مدیریتی برای نمایندگان شامل: - **داشبورد**: نمای کلی آمار - **حساب کاربری**: مدیریت پروفایل - **افزودن پزشک**: ثبت پزشک جدید - **مدیریت نوبت‌ها**: مشاهده و مدیریت نوبت‌ها **محافظت مسیر:** ```javascript // app/panel/(layout)/layout.js async function LayoutPanel({ children }) { const user = await getUser(); const ability = defineAbilitiesFor(user); if (!ability.can("access", "Panel")) { return redirect("/"); } return {children}; } ``` --- ## 🚀 راه‌اندازی پروژه ### پیش‌نیازها - **Node.js** 18+ - **npm** یا **yarn** - **Docker** (اختیاری) ### نصب و راه‌اندازی ```bash # 1. کلون کردن پروژه git clone [repository-url] cd nobat724_front # 2. نصب وابستگی‌ها npm install # یا yarn install # 3. ایجاد فایل .env.local cp .env.example .env.local # 4. تنظیم متغیرهای محیطی # ویرایش .env.local: NEXT_PUBLIC_API_URL=http://localhost:8000 NEXT_PUBLIC_CLIENT_ID=your_client_id NEXT_PUBLIC_CLIENT_SECRET=your_client_secret DEV_MODE=TRUE # 5. اجرای پروژه در حالت Development npm run dev # یا yarn dev # پروژه در http://localhost:3000 اجرا می‌شود ``` ### اسکریپت‌های موجود ```json { "dev": "cross-env HOST=yazd-nobat.localhost PORT=3000 next dev", "build": "next build", "start": "next start", "lint": "next lint" } ``` ### راه‌اندازی با Docker ```bash # Build و اجرا docker-compose up -d # مشاهده لاگ‌ها docker-compose logs -f # توقف docker-compose down ``` --- ## 🌐 سیستم Multi-Domain ### ساختار دامنه‌ها پروژه از **subdomain-based routing** استفاده می‌کند: ``` nobat724.com → سایت اصلی (همه شهرها) tabriz-nobat.ir → تبریز urmia-nobat.ir → ارومیه yazd-nobat.ir → یزد ``` ### فرآیند تشخیص شهر ```javascript // lib/getStateInfo.js (Server-Side) export function getStateInfo() { const headersList = headers(); const host = headersList.get("host") || ""; const subdomain = host.split(".")[0]; const matchedCity = citiesData.find((city) => city.domain.includes(subdomain) ); return { matchedCity, matchedState }; } // context/ProvinceProvider.js (Client-Side) export const ProvinceProvider = ({ children }) => { const [hostName, setHostName] = useState(""); const isProvinceInclude = citiesData.find((city) => hostName.includes(city.domain.split(".")[0]) ); return ( {children} ); }; ``` ### Metadata داینامیک بر اساس شهر ```javascript // app/layout.js export async function generateMetadata() { const { matchedCity } = getStateInfo(); return { title: matchedCity ? matchedCity.title : "نوبت724", description: matchedCity ? matchedCity.description : "توضیحات پیش‌فرض", keywords: matchedCity ? matchedCity.keywords : "کلمات کلیدی پیش‌فرض", }; } ``` --- ## 🔐 احراز هویت و مجوزها ### فرآیند ورود 1. **ورود شماره موبایل** (`/login`) 2. **دریافت کد OTP** 3. **تایید کد** (`/login-verify`) 4. **ذخیره توکن‌ها در Cookie** 5. **Redirect به Dashboard یا Panel** ### Cookies استفاده شده - `access_token`: JWT Token - `refresh_token`: Refresh Token - `uuid`: شناسه کاربر - `userInfo`: اطلاعات کاربر ### محافظت از مسیرها **مثال - محافظت از Panel:** ```javascript // app/panel/(layout)/layout.js async function LayoutPanel({ children }) { const user = await getUser(); const ability = defineAbilitiesFor(user); if (!ability.can("access", "Panel")) { return redirect("/"); } return {children}; } ``` **مثال - محافظت از صفحه Login:** ```javascript // app/login/page.js async function LogIn() { const user = await getUser(); const ability = defineAbilitiesFor(user); if (!ability.can("access", "Login")) { return redirect("/"); } return ; } ``` --- ## 📍 مسیرها و صفحات ### صفحات عمومی (Public) | مسیر | توضیحات | فایل | | ---------------- | -------------- | --------------------------- | | `/` | صفحه اصلی | `app/page.js` | | `/doctors` | لیست پزشکان | `app/doctors/page.js` | | `/doctor/[slug]` | جزئیات پزشک | `app/doctor/[slug]/page.js` | | `/clinics` | لیست کلینیک‌ها | `app/clinics/page.js` | | `/clinic/[slug]` | جزئیات کلینیک | `app/clinic/[slug]/page.js` | | `/specialties` | تخصص‌های پزشکی | `app/specialties/page.js` | | `/blogs` | لیست بلاگ‌ها | `app/blogs/page.js` | | `/blog/[slug]` | جزئیات بلاگ | `app/blog/[slug]/page.js` | | `/about-us` | درباره ما | `app/about-us/page.js` | | `/contact-us` | تماس با ما | `app/contact-us/page.js` | ### صفحات رزرو نوبت | مسیر | توضیحات | | ------------------------- | -------------- | | `/appointment/[doctorId]` | صفحه رزرو نوبت | ### صفحات احراز هویت | مسیر | توضیحات | محافظت | | --------------- | --------- | ----------------- | | `/login` | ورود | فقط کاربران مهمان | | `/login-verify` | تایید OTP | فقط کاربران مهمان | ### پنل مدیریتی (Protected) | مسیر | توضیحات | دسترسی | | --------------------- | -------------- | --------- | | `/panel/dashboard` | داشبورد | نمایندگان | | `/panel/user-account` | حساب کاربری | نمایندگان | | `/panel/add-doctor` | افزودن پزشک | نمایندگان | | `/panel/turns` | مدیریت نوبت‌ها | نمایندگان | --- ## 🧩 کامپوننت‌های اصلی ### Layout Components **1. Root Layout (`app/layout.js`)** - Metadata داینامیک - Theme Provider - Province Provider - Google Analytics - Custom Toastify **2. Public Layout (`components/layout/StLayout.js`)** - Header - Footer - ScrollToTop **3. Panel Layout (`components/layoutPanel/`)** - Sidebar - Header - User Detail ### Feature Components **Home Page (`components/home/`)** - Search Bar - Text Header - Frequent Searches **Doctor List (`components/doctors/`)** - Filter Sidebar - Doctor Cards - Pagination **Doctor Detail (`components/doctor/`)** - Doctor Info - Appointment List - Comments - Share **Appointment (`components/appointment/`)** - Date Picker - Time Slots - Patient Details - Payment - Success/Fail Pages **Panel (`components/panel/`)** - Dashboard Stats - Doctor Management - Appointment Management - User Profile --- ## 🔌 API و سرویس‌ها ### تنظیمات Axios (`services/api.js`) ```javascript const BASE_URL = process.env.NEXT_PUBLIC_API_URL; const token = Cookies.get("access_token"); const api = axios.create({ baseURL: BASE_URL, headers: { "Content-Type": "application/json", Authorization: token ? `Bearer ${token}` : "", }, }); api.interceptors.response.use( (response) => response.data, (error) => Promise.reject(error) ); ``` ### API Endpoints (`services/response.js`) **دسته‌بندی Endpoints:** ```javascript // Authentication postLogin(data); getUserInfo(headers); // Doctors getDoctors(params); getDoctor(slug); postDoctor(data); getDoctorServices(); // Clinics getClinics(params); getClinic(slug); getClinicDoctors(slug, params); // Appointments getAppointment(doctor_id, date); postAppointment(data); getAppointmentNotAvailable(doctor_id); getAppointmentWeeklySchedule(uuid); postAppointmentWeeklySchedule(); patchAppointmentWeeklySchedule(uuid); deleteAppointmentWeeklySchedule(uuid); // User Profile getUserProfile(uuid); postUserProfile(data); patchUserProfile(data, uuid, token); // Categories getSpecialties(); getInsuranceType(); // File Upload postImageUpload(data); ``` ### Helper Functions (`helper/index.js`) ```javascript // تبدیل اعداد به فرمت عربی export const numberToArStyle = (num) => num?.toLocaleString("ar-AE") || ""; // تبدیل تاریخ میلادی به شمسی export const convertToJalali = (date) => { const jalaliDate = moment(date).format("jYYYY/jM/jD"); // ... }; // بررسی URL فعال export const isActiveURL = (link, name) => link === name; // آپلود تصویر export const uploadImage = async (event) => { // ... }; // ساخت Query String برای فیلتر پزشکان export const buildDoctorParams = (searchParams) => { // ... }; ``` --- ## 🎨 استایل‌دهی ### Tailwind CSS پروژه از **Tailwind CSS** برای استایل‌دهی استفاده می‌کند: ```javascript // tailwind.config.js module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", "./app/**/*.{js,ts,jsx,tsx,mdx}", ], darkMode: "class", theme: { extend: { // Custom colors, fonts, etc. }, }, }; ``` ### Material-UI Theme ```javascript // mui/index.js const theme = createTheme({ direction: "rtl", typography: { fontFamily: "IRANSans, Arial", }, palette: { primary: { main: "#5559CE" }, // ... }, }); ``` ### Dark Mode ```javascript // app/Providers.js export function Providers({ children }) { const router = usePathname(); return ( {children} ); } ``` --- ## 🐳 Deployment ### متغیرهای محیطی مورد نیاز ```env # API Configuration NEXT_PUBLIC_API_URL=https://api.nobat724.com NEXT_PUBLIC_CLIENT_ID=your_client_id NEXT_PUBLIC_CLIENT_SECRET=your_client_secret # Development Mode (TRUE/FALSE) DEV_MODE=FALSE # Application Port APP_PORT=3000 # Node Environment NODE_ENV=production ``` ### Build Production ```bash # Build npm run build # Start Production Server npm run start ``` ### Docker Deployment ```bash # Build Image docker build -t nobat724-front . # Run Container docker run -p 3000:3000 \ -e NEXT_PUBLIC_API_URL=https://api.nobat724.com \ -e DEV_MODE=FALSE \ nobat724-front ``` ### Docker Compose ```yaml # docker-compose.yml version: "3.8" services: frontend: build: context: . dockerfile: Dockerfile restart: unless-stopped ports: - "${APP_PORT}:3000" environment: - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} - DEV_MODE=${DEV_MODE} ``` --- ## 📝 نکات توسعه ### 1. افزودن صفحه جدید ```javascript // app/new-page/page.js import Layout from "@/components/layout/StLayout"; export default function NewPage() { return (
محتوای صفحه جدید
); } ``` ### 2. افزودن API Endpoint جدید ```javascript // services/response.js export const request = { // ... getNewData: () => api.get("api/v1/new-endpoint"), postNewData: (data) => api.post("api/v1/new-endpoint", data), }; ``` ### 3. افزودن کامپوننت جدید ```javascript // components/NewComponent/index.js "use client"; // اگر Client Component است function NewComponent({ data }) { return
{/* محتوای کامپوننت */}
; } export default NewComponent; ``` ### 4. کار با تاریخ شمسی ```javascript import moment from "jalali-moment"; // تبدیل میلادی به شمسی const jalaliDate = moment("2024-01-15").format("jYYYY/jMM/jDD"); // تبدیل شمسی به میلادی const gregorianDate = moment("1402/10/25", "jYYYY/jMM/jDD").format( "YYYY-MM-DD" ); ``` ### 5. استفاده از Context ```javascript "use client"; import { useProvince } from "@/context/ProvinceProvider"; function MyComponent() { const { isProvinceInclude } = useProvince(); return
{isProvinceInclude &&

شهر: {isProvinceInclude.name}

}
; } ``` --- ## 🔧 Troubleshooting ### مشکلات رایج **1. خطای Hydration** ``` Error: Text content does not match server-rendered HTML ``` **راه‌حل:** استفاده از `useEffect` برای محتوای Client-Side **2. خطای Authentication** ``` Unauthorized (401) ``` **راه‌حل:** بررسی توکن در Cookie و تنظیم Header **3. مشکل Dark Mode** ``` Flash of unstyled content ``` **راه‌حل:** استفاده صحیح از `next-themes` و `ThemeProvider` --- ## 📚 منابع مفید - [Next.js Documentation](https://nextjs.org/docs) - [Material-UI Documentation](https://mui.com/) - [Tailwind CSS Documentation](https://tailwindcss.com/docs) - [CASL Documentation](https://casl.js.org/v6/en/) - [Jalali Moment](https://github.com/jalaali/moment-jalaali) --- ## 👥 تیم توسعه **Senior Frontend Developer**: شما! 🎉 **Tech Stack Expertise:** - ✅ Next.js 14 (App Router) - ✅ React.js 18 - ✅ Material-UI v7 - ✅ Tailwind CSS - ✅ Server Components & Client Components - ✅ Authentication & Authorization - ✅ Multi-Domain Architecture - ✅ Persian/Jalali Date Handling --- ## 📞 پشتیبانی برای هرگونه سوال یا مشکل: - 📧 Email: nobat724@gmail.com - 🌐 Website: https://nobat724.com --- **تاریخ آخرین به‌روزرسانی:** نوامبر 2025 **نسخه پروژه:** 0.1.0