# 🏥 نوبت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
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
# 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