feat: add comprehensive project documentation in PROJECT.md
This commit is contained in:
+985
@@ -0,0 +1,985 @@
|
||||
# ClinicPro — مستندات کامل پروژه
|
||||
|
||||
> **تاریخ آخرین بهروزرسانی:** ۱۴۰۵/۰۳/۱۹ | **نسخه Symfony:** 7.4 | **PHP:** ≥ 8.2
|
||||
|
||||
---
|
||||
|
||||
## فهرست مطالب
|
||||
|
||||
1. [معرفی پروژه](#۱-معرفی-پروژه)
|
||||
2. [تکنولوژی Stack](#۲-تکنولوژی-stack)
|
||||
3. [ساختار دایرکتوری](#۳-ساختار-دایرکتوری)
|
||||
4. [راهاندازی محیط توسعه](#۴-راهاندازی-محیط-توسعه)
|
||||
5. [متغیرهای محیطی](#۵-متغیرهای-محیطی)
|
||||
6. [پایگاه داده — موجودیتها](#۶-پایگاه-داده--موجودیتها)
|
||||
7. [API Endpoints](#۷-api-endpoints)
|
||||
8. [امنیت و احراز هویت](#۸-امنیت-و-احراز-هویت)
|
||||
9. [پنل ادمین React](#۹-پنل-ادمین-react)
|
||||
10. [Frontend Build](#۱۰-frontend-build)
|
||||
11. [دستورات Console](#۱۱-دستورات-console)
|
||||
12. [Migrations](#۱۲-migrations)
|
||||
13. [سرویسهای خارجی](#۱۳-سرویسهای-خارجی)
|
||||
|
||||
---
|
||||
|
||||
## ۱. معرفی پروژه
|
||||
|
||||
**ClinicPro** یک سیستم جامع مدیریت کلینیک و نوبتدهی پزشکی است که شامل:
|
||||
|
||||
- **API Backend:** Symfony 7.4 (REST API + JWT Auth)
|
||||
- **Admin Panel:** React 19 + TypeScript (SPA داخل Symfony)
|
||||
- **ویژگیهای اصلی:**
|
||||
- مدیریت پزشکان، کلینیکها و کاربران
|
||||
- سیستم نوبتدهی با مدیریت اسلات زمانی
|
||||
- درگاه پرداخت (ملت و سپ)
|
||||
- سیستم کیف پول و تسویهحساب
|
||||
- نمایندگان (Representation) با کمیسیون
|
||||
- احراز هویت OTP + رمز عبور
|
||||
- مدیریت منشی با دسترسیهای دانهای
|
||||
- ارسال پیامک (KaveNegar / Rangineh)
|
||||
- امتیاز و نظرات پزشکان
|
||||
- بلاگ
|
||||
|
||||
---
|
||||
|
||||
## ۲. تکنولوژی Stack
|
||||
|
||||
### Backend
|
||||
| لایه | تکنولوژی |
|
||||
|------|----------|
|
||||
| Framework | Symfony 7.4 |
|
||||
| PHP | >= 8.2 |
|
||||
| ORM | Doctrine ORM 3.6 |
|
||||
| Auth | JWT (lexik/jwt-authentication-bundle) |
|
||||
| Queue | Symfony Messenger |
|
||||
| Cache/Session | Redis |
|
||||
| Database | MySQL |
|
||||
| API Docs | NelmioApiDocBundle (Swagger) |
|
||||
| Rate Limiting | Symfony Rate Limiter |
|
||||
|
||||
### Frontend (Admin)
|
||||
| لایه | تکنولوژی |
|
||||
|------|----------|
|
||||
| Framework | React 19 + TypeScript |
|
||||
| Routing | React Router DOM v7 |
|
||||
| Styling | Tailwind CSS v4 |
|
||||
| State (server) | TanStack Query v5 |
|
||||
| State (client) | Zustand v5 |
|
||||
| Forms | React Hook Form + Zod |
|
||||
| Icons | Heroicons v2 |
|
||||
| Toast | Sonner |
|
||||
| Tables | TanStack Table v8 |
|
||||
| Build | Webpack Encore (Symfony UX React) |
|
||||
|
||||
---
|
||||
|
||||
## ۳. ساختار دایرکتوری
|
||||
|
||||
```
|
||||
clinic-pro-symfony/
|
||||
├── assets/
|
||||
│ ├── admin/ ← React Admin SPA
|
||||
│ │ ├── index.tsx ← Entry point
|
||||
│ │ ├── App.tsx ← Router + PrivateRoute
|
||||
│ │ ├── styles.css ← Tailwind CSS v4
|
||||
│ │ ├── components/
|
||||
│ │ │ └── layout/
|
||||
│ │ │ ├── AdminLayout.tsx
|
||||
│ │ │ ├── Sidebar.tsx
|
||||
│ │ │ └── Topbar.tsx
|
||||
│ │ ├── pages/
|
||||
│ │ │ ├── LoginPage.tsx
|
||||
│ │ │ └── DashboardPage.tsx
|
||||
│ │ ├── stores/
|
||||
│ │ │ ├── authStore.ts ← Zustand JWT store
|
||||
│ │ │ └── uiStore.ts ← Sidebar state
|
||||
│ │ ├── hooks/
|
||||
│ │ └── lib/
|
||||
│ ├── app.js ← Symfony main entry
|
||||
│ ├── styles/app.css
|
||||
│ └── react/controllers/ ← UX React controllers
|
||||
│
|
||||
├── config/
|
||||
│ ├── packages/
|
||||
│ │ ├── security.yaml ← Firewalls + ACL
|
||||
│ │ ├── doctrine.yaml
|
||||
│ │ ├── lexik_jwt_authentication.yaml
|
||||
│ │ ├── messenger.yaml
|
||||
│ │ ├── rate_limiter.yaml
|
||||
│ │ └── webpack_encore.yaml
|
||||
│ └── routes/
|
||||
│ ├── security.yaml
|
||||
│ └── nelmio_api_doc.yaml
|
||||
│
|
||||
├── migrations/ ← 16 Doctrine migrations
|
||||
│
|
||||
├── public/
|
||||
│ ├── index.php
|
||||
│ └── build/ ← Webpack output
|
||||
│
|
||||
├── src/
|
||||
│ ├── Admin/Controller/ ← SPA catch-all
|
||||
│ ├── Appointment/ ← نوبتدهی
|
||||
│ ├── Auth/ ← احراز هویت
|
||||
│ ├── Blog/ ← بلاگ
|
||||
│ ├── Category/ ← دستهبندیها
|
||||
│ ├── Clinic/ ← کلینیکها
|
||||
│ ├── Doctor/ ← پزشکان
|
||||
│ ├── Insurance/ ← بیمه
|
||||
│ ├── Payment/ ← پرداخت
|
||||
│ ├── Rating/ ← امتیاز و نظرات
|
||||
│ ├── Representation/ ← نمایندگان
|
||||
│ ├── Secretary/ ← منشیها
|
||||
│ ├── Settlement/ ← تسویهحساب
|
||||
│ ├── Shared/ ← زیرساخت مشترک
|
||||
│ ├── Sms/ ← پیامک
|
||||
│ ├── UserProfile/ ← پروفایل کاربر
|
||||
│ └── Kernel.php
|
||||
│
|
||||
├── tests/
|
||||
├── webpack.config.js
|
||||
├── tsconfig.json
|
||||
├── postcss.config.js
|
||||
├── composer.json
|
||||
├── package.json
|
||||
└── .env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۴. راهاندازی محیط توسعه
|
||||
|
||||
### پیشنیازها
|
||||
- [ddev](https://ddev.readthedocs.io/) نصب شده
|
||||
- Docker Desktop
|
||||
|
||||
### مراحل اجرا
|
||||
|
||||
```bash
|
||||
# ۱. کلون پروژه
|
||||
git clone <repo-url>
|
||||
cd clinic-pro-symfony
|
||||
|
||||
# ۲. راهاندازی ddev
|
||||
ddev start
|
||||
|
||||
# ۳. نصب PHP packages
|
||||
ddev composer install
|
||||
|
||||
# ۴. ساخت JWT keys
|
||||
ddev exec php bin/console lexik:jwt:generate-keypair
|
||||
|
||||
# ۵. اجرای migrations
|
||||
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
|
||||
|
||||
# ۶. نصب npm packages
|
||||
npm install --legacy-peer-deps
|
||||
|
||||
# ۷. Build frontend (dev)
|
||||
npm run dev
|
||||
|
||||
# ۸. یا watch mode
|
||||
npm run watch
|
||||
```
|
||||
|
||||
### دسترسی
|
||||
| سرویس | آدرس |
|
||||
|-------|------|
|
||||
| Admin Panel | https://clinic-pro.ddev.site/admin |
|
||||
| API | https://clinic-pro.ddev.site/api/v1 |
|
||||
| Swagger UI | https://clinic-pro.ddev.site/api/doc |
|
||||
| Health Check | https://clinic-pro.ddev.site/health |
|
||||
|
||||
### اطلاعات ادمین پیشفرض
|
||||
| فیلد | مقدار |
|
||||
|------|-------|
|
||||
| موبایل | `09120671713` |
|
||||
| رمز عبور | `admin1234` |
|
||||
| نقش | `ROLE_ADMIN` |
|
||||
|
||||
---
|
||||
|
||||
## ۵. متغیرهای محیطی
|
||||
|
||||
فایل `.env` — کلیدها (مقادیر در `.env.local` تنظیم میشوند):
|
||||
|
||||
```env
|
||||
APP_ENV=dev|prod
|
||||
APP_SECRET= # کلید امنیتی Symfony
|
||||
APP_SHARE_DIR= # مسیر shared assets
|
||||
DEFAULT_URI= # آدرس پایه سایت (مثلاً https://clinic-pro.ddev.site)
|
||||
|
||||
DATABASE_URL= # DSN پایگاه داده MySQL
|
||||
|
||||
JWT_SECRET_KEY= # مسیر کلید خصوصی JWT
|
||||
JWT_PUBLIC_KEY= # مسیر کلید عمومی JWT
|
||||
JWT_PASSPHRASE= # رمز کلید JWT
|
||||
|
||||
CORS_ALLOW_ORIGIN= # آدرسهای مجاز CORS
|
||||
|
||||
MESSENGER_TRANSPORT_DSN= # DSN صف پیام (Redis)
|
||||
REDIS_URL= # آدرس Redis
|
||||
|
||||
REFRESH_TOKEN_TTL=2592000 # عمر refresh token (ثانیه) = ۳۰ روز
|
||||
OTP_TTL=1200 # عمر کد OTP (ثانیه) = ۲۰ دقیقه
|
||||
|
||||
# SMS - KaveNegar
|
||||
KAVENEGAR_API_KEY=
|
||||
KAVENEGAR_SENDER=
|
||||
# SMS - Rangineh
|
||||
RANGINEH_API_KEY=
|
||||
RANGINEH_SENDER=
|
||||
SMS_PROVIDER=kavenegar|rangineh # ارائهدهنده فعال
|
||||
|
||||
# File Upload
|
||||
MAX_FILE_SIZE_BYTES=5242880 # حداکثر حجم فایل (۵ مگابایت)
|
||||
UPLOAD_DIR= # مسیر ذخیره فایلها
|
||||
|
||||
ALLOWED_FRONTEND_HOSTS= # هاستهای مجاز برای redirect پرداخت
|
||||
|
||||
# Payment - Mellat Bank
|
||||
MELLAT_TERMINAL_ID=
|
||||
MELLAT_USERNAME=
|
||||
MELLAT_PASSWORD=
|
||||
|
||||
# Payment - SEP (Saman)
|
||||
SEP_TERMINAL_ID=
|
||||
|
||||
APP_BASE_URL= # آدرس پایه برای callback پرداخت
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۶. پایگاه داده — موجودیتها
|
||||
|
||||
### جداول پایگاه داده
|
||||
|
||||
| جدول | Entity | توضیح |
|
||||
|------|--------|-------|
|
||||
| `users` | `Auth\Entity\User` | کاربران سیستم |
|
||||
| `doctors` | `Doctor\Entity\Doctor` | پروفایل پزشکان |
|
||||
| `doctor_addresses` | `Doctor\Entity\DoctorAddress` | آدرس مطب |
|
||||
| `clinics` | `Clinic\Entity\Clinic` | کلینیکها |
|
||||
| `categories` | `Category\Entity\Category` | دستهبندیها |
|
||||
| `appointments` | `Appointment\Entity\Appointment` | نوبتها |
|
||||
| `weekly_schedules` | `Appointment\Entity\WeeklySchedule` | برنامه هفتگی |
|
||||
| `date_overrides` | `Appointment\Entity\DateOverride` | تغییر برنامه خاص |
|
||||
| `holidays` | `Appointment\Entity\Holiday` | تعطیلات |
|
||||
| `payments` | `Payment\Entity\Payment` | پرداختها |
|
||||
| `settlements` | `Settlement\Entity\Settlement` | درخواست تسویه |
|
||||
| `wallet_transactions` | `Settlement\Entity\WalletTransaction` | تراکنش کیف پول |
|
||||
| `representations` | `Representation\Entity\Representation` | نمایندگان |
|
||||
| `doctor_secretaries` | `Secretary\Entity\DoctorSecretary` | منشیهای پزشک |
|
||||
| `comments` | `Rating\Entity\Comment` | نظرات |
|
||||
| `rates` | `Rating\Entity\Rate` | امتیازها |
|
||||
| `likes` | `Rating\Entity\Like` | لایک نظرات |
|
||||
| `blogs` | `Blog\Entity\Blog` | مقالات بلاگ |
|
||||
| `sms_templates` | `Sms\Entity\SmsTemplate` | قالبهای پیامک |
|
||||
| `sms_logs` | `Sms\Entity\SmsLog` | لاگ ارسال پیامک |
|
||||
| `profiles` | `UserProfile\Entity\UserProfile` | پروفایل پزشکی کاربر |
|
||||
| `doctor_insurances` | `Insurance\Entity\DoctorInsurance` | بیمههای پزشک |
|
||||
|
||||
### جداول Join (ManyToMany)
|
||||
| جدول | رابطه |
|
||||
|------|-------|
|
||||
| `doctor_specialties` | Doctor ↔ Category (specialty) |
|
||||
| `doctor_expertise` | Doctor ↔ Category (expertise) |
|
||||
| `doctor_states` | Doctor ↔ Category (state) |
|
||||
| `doctor_cities` | Doctor ↔ Category (city) |
|
||||
| `clinic_doctors` | Clinic ↔ Doctor |
|
||||
| `clinic_specialties` | Clinic ↔ Category |
|
||||
| `clinic_services` | Clinic ↔ Category |
|
||||
| `clinic_insurances` | Clinic ↔ Category |
|
||||
|
||||
---
|
||||
|
||||
### User (users)
|
||||
|
||||
```
|
||||
id INT PK AUTO_INCREMENT
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
mobile_number VARCHAR(20) UNIQUE ← شناسه ورود
|
||||
password_hash VARCHAR(255) nullable
|
||||
email VARCHAR(100) nullable
|
||||
real_name VARCHAR(100) nullable
|
||||
roles JSON ← ['ROLE_USER', 'ROLE_ADMIN', ...]
|
||||
status SMALLINT default:1 ← 1=active, 0=inactive
|
||||
created_at INT (unix timestamp)
|
||||
updated_at INT (unix timestamp)
|
||||
```
|
||||
|
||||
**نقشهای موجود:** `ROLE_USER` | `ROLE_ADMIN` | `ROLE_DOCTOR` | `ROLE_CLINIC` | `ROLE_REPRESENTATION` | `ROLE_SECRETARY`
|
||||
|
||||
---
|
||||
|
||||
### Doctor (doctors)
|
||||
|
||||
```
|
||||
id INT PK
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
user_id INT FK → users
|
||||
name VARCHAR(255)
|
||||
gender VARCHAR(10) nullable
|
||||
medical_system_code VARCHAR(25) nullable
|
||||
mobile_number VARCHAR(15) nullable
|
||||
activity_time INT nullable ← مدت ویزیت (دقیقه)
|
||||
degree VARCHAR(30) nullable ← general/specialist/subspecialist
|
||||
info TEXT nullable
|
||||
images JSON nullable
|
||||
doctor_rate FLOAT default:3.5
|
||||
doctor_rate_percentage FLOAT default:60.0 ← سهم پزشک از پرداخت (%)
|
||||
active_doctor_appointment BOOL default:true
|
||||
representation_id INT nullable
|
||||
created_at / updated_at INT
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Clinic (clinics)
|
||||
|
||||
```
|
||||
id INT PK
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
user_id INT FK → users
|
||||
name VARCHAR(255) nullable
|
||||
info TEXT nullable
|
||||
address TEXT nullable
|
||||
telephone VARCHAR(50) nullable
|
||||
is_24_7 BOOL default:false
|
||||
working_days VARCHAR(255) nullable
|
||||
latitude/longitude FLOAT nullable
|
||||
city_id INT nullable → categories
|
||||
state_id INT nullable → categories
|
||||
representation_id INT nullable
|
||||
images_clinic JSON nullable
|
||||
clinic_logo JSON nullable
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Appointment (appointments)
|
||||
|
||||
```
|
||||
id INT PK
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
doctor_id INT FK → doctors
|
||||
user_id INT FK → users
|
||||
slot_start INT (unix timestamp)
|
||||
slot_end INT (unix timestamp)
|
||||
status VARCHAR(30)
|
||||
note VARCHAR(255) nullable
|
||||
version INT (optimistic locking)
|
||||
```
|
||||
|
||||
**وضعیتهای نوبت:**
|
||||
```
|
||||
waiting_for_payment → در انتظار پرداخت
|
||||
reserved → رزرو شده
|
||||
checked_in → ورود به مطب
|
||||
waiting → در صف انتظار
|
||||
in_progress → در حال ویزیت
|
||||
visited → ویزیت شده
|
||||
completed → تکمیل شده
|
||||
cancelled_by_doctor → لغو توسط پزشک
|
||||
cancelled_by_user → لغو توسط کاربر
|
||||
auto_cancel_unpaid → لغو خودکار (پرداختنشده)
|
||||
no_show → غیبت
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Payment (payments)
|
||||
|
||||
```
|
||||
id INT PK
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
order_id VARCHAR(64) UNIQUE
|
||||
user_id INT FK
|
||||
appointment_id INT FK nullable
|
||||
amount_rials INT
|
||||
status VARCHAR(30) ← pending|success|failed|refunded
|
||||
gateway VARCHAR(20) ← mellat|sep
|
||||
type VARCHAR(30) ← appointment|subscription
|
||||
gateway_token VARCHAR(255) nullable
|
||||
reference_id VARCHAR(255) nullable
|
||||
frontend_address VARCHAR(500) nullable
|
||||
callback_ip VARCHAR(45) nullable
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Category (categories)
|
||||
|
||||
```
|
||||
id INT PK
|
||||
uuid VARCHAR(36) UNIQUE
|
||||
bundle VARCHAR(32) ← نوع دستهبندی
|
||||
label VARCHAR(255) nullable
|
||||
status SMALLINT default:1
|
||||
parent_id INT nullable ← برای city → state
|
||||
weight INT default:0
|
||||
representation_id INT nullable
|
||||
```
|
||||
|
||||
**نوعهای bundle:**
|
||||
```
|
||||
state ← استانها
|
||||
city ← شهرها (parent_id = state)
|
||||
specially_doctor ← تخصص پزشک
|
||||
doctor_services ← خدمات پزشک
|
||||
insurance_type ← نوع بیمه پایه
|
||||
supplementary_insurance ← بیمه تکمیلی
|
||||
tag ← تگ بلاگ
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Settlement + Wallet
|
||||
|
||||
```sql
|
||||
-- settlements
|
||||
uuid, user_id, amount_rials, status(pending|approved|rejected|paid),
|
||||
bank_account(JSON), admin_note, reviewed_by, reviewed_at
|
||||
|
||||
-- wallet_transactions
|
||||
user_id, amount, type(credit|debit), balance_after, description
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DoctorSecretary
|
||||
|
||||
```
|
||||
uuid
|
||||
doctor_id FK → doctors
|
||||
secretary_id FK → users
|
||||
permission JSON:
|
||||
{
|
||||
"appointments": { "view": true, "create": true, "cancel": false, "update_status": false },
|
||||
"addresses": { "view": true, "create": false, "update": false, "delete": false },
|
||||
"clinic_info": { "view": true, "update": false },
|
||||
"insurances": { "view": true, "create": false, "update": false, "delete": false }
|
||||
}
|
||||
active BOOL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۷. API Endpoints
|
||||
|
||||
### Base URL: `https://clinic-pro.ddev.site`
|
||||
|
||||
---
|
||||
|
||||
### 🔐 Auth (`/api/v1/user/` & `/oauth/`)
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| POST | `/api/v1/user/login` | Public | ورود با موبایل و رمز → JWT + refresh |
|
||||
| POST | `/api/v1/user/send-code` | Public | ارسال کد OTP به موبایل |
|
||||
| POST | `/api/v1/user/verify-code` | Public | تأیید کد OTP |
|
||||
| POST | `/api/v1/user/register` | Public | ثبتنام کاربر جدید |
|
||||
| POST | `/oauth/token` | Public | دریافت JWT با موبایل (mobile grant) |
|
||||
| POST | `/oauth/token/refresh` | Public | تمدید JWT با refresh token |
|
||||
| GET | `/oauth/userinfo` | ✅ | اطلاعات کاربر جاری |
|
||||
| POST | `/oauth/logout` | ✅ | خروج و ابطال refresh token |
|
||||
| GET | `/session/token` | Public | دریافت CSRF session token |
|
||||
|
||||
**درخواست Login:**
|
||||
```json
|
||||
POST /api/v1/user/login
|
||||
{ "mobile_number": "09120671713", "password": "admin1234" }
|
||||
```
|
||||
**پاسخ موفق:**
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJ...",
|
||||
"refresh_token": "8e75...",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600,
|
||||
"refresh_token_expires_in": 2592000
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 👥 Users
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/oauth/userinfo` | ✅ | پروفایل کاربر جاری |
|
||||
| DELETE | `/api/v1/user/{id}` | ADMIN | حذف کاربر |
|
||||
|
||||
---
|
||||
|
||||
### 🩺 Doctors
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/doctors` | Public | لیست پزشکان (فیلتر + pagination) |
|
||||
| GET | `/api/v1/doctor/{uuid}` | Public | جزئیات پزشک |
|
||||
| POST | `/api/v1/doctor` | ✅ | ایجاد پروفایل پزشک |
|
||||
| PATCH | `/api/v1/doctor/{uuid}` | ✅ | بهروزرسانی پروفایل |
|
||||
| DELETE | `/api/v1/doctor/{uuid}` | ADMIN | حذف پزشک |
|
||||
| POST | `/file/upload/clinic_pro/doctor/field_image` | ✅ | آپلود تصویر |
|
||||
| GET | `/api/v1/clinic-pro/doctor-addresses/{doctorId}` | Public | لیست آدرسها |
|
||||
| POST | `/api/v1/clinic-pro/doctor-address` | ✅ | افزودن آدرس |
|
||||
| PATCH | `/api/v1/clinic-pro/doctor-address/{id}` | ✅ | ویرایش آدرس |
|
||||
| DELETE | `/api/v1/clinic-pro/doctor-address/{id}` | ✅ | حذف آدرس |
|
||||
|
||||
---
|
||||
|
||||
### 🏥 Clinics
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/clinics` | Public | لیست کلینیکها |
|
||||
| GET | `/api/v1/clinic/{uuid}` | Public | جزئیات کلینیک |
|
||||
| POST | `/api/v1/clinic` | ✅ | ایجاد کلینیک |
|
||||
| PATCH | `/api/v1/clinic/{uuid}` | ✅ | ویرایش کلینیک |
|
||||
| GET | `/api/v1/clinic/doctor-list/{clinicUuid}` | Public | پزشکان کلینیک |
|
||||
| POST | `/file/upload/clinic_pro/clinic/field_image_clinic` | ✅ | آپلود تصویر |
|
||||
| POST | `/file/upload/clinic_pro/clinic/field_clinic_logo` | ✅ | آپلود لوگو |
|
||||
|
||||
---
|
||||
|
||||
### 📅 Appointments
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/appointment-slots` | Public | اسلاتهای خالی پزشک |
|
||||
| POST | `/api/v1/appointment` | ✅ | رزرو نوبت |
|
||||
| GET | `/api/v1/appointment/{uuid}` | ✅ | جزئیات نوبت |
|
||||
| PATCH | `/api/v1/appointment/{uuid}/status` | ✅ | تغییر وضعیت نوبت |
|
||||
| GET | `/api/v1/appointments/doctor/{doctorUuid}` | ✅ | نوبتهای پزشک |
|
||||
| GET | `/api/v1/appointments/user` | ✅ | نوبتهای کاربر |
|
||||
|
||||
**تنظیمات نوبتدهی:**
|
||||
|
||||
| Method | Path | توضیح |
|
||||
|--------|------|-------|
|
||||
| POST | `/api/v1/appointment-settings/weekly-schedule` | برنامه هفتگی |
|
||||
| POST | `/api/v1/appointment-settings/date-override` | تغییر برنامه خاص |
|
||||
| POST | `/api/v1/appointment-settings/holidays` | ثبت تعطیلات |
|
||||
|
||||
---
|
||||
|
||||
### 💳 Payments
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| POST | `/api/v1/payment/appointment` | ✅ | شروع پرداخت نوبت |
|
||||
| GET/POST | `/api/v1/payment/callback/{gateway}` | Public (IP) | callback درگاه |
|
||||
| GET | `/api/v1/payment/{uuid}` | ✅ | وضعیت پرداخت |
|
||||
| POST | `/api/v1/subscription-payment` | ✅ | پرداخت اشتراک |
|
||||
|
||||
**پارامتر `{gateway}`:** `mellat` یا `sep`
|
||||
|
||||
---
|
||||
|
||||
### 🏦 Settlement & Wallet
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/wallet/balance` | ✅ | موجودی کیف پول |
|
||||
| GET | `/api/v1/wallet/transactions` | ✅ | تاریخچه تراکنشها |
|
||||
| POST | `/api/v1/settlement` | ✅ | درخواست تسویه |
|
||||
| GET | `/api/v1/settlement` | ✅ | لیست درخواستها |
|
||||
| GET | `/api/v1/settlement/{uuid}` | ✅ | جزئیات درخواست |
|
||||
| POST | `/api/v1/settlement/{uuid}/approve` | ADMIN | تأیید تسویه |
|
||||
| POST | `/api/v1/settlement/{uuid}/reject` | ADMIN | رد تسویه |
|
||||
|
||||
---
|
||||
|
||||
### ⭐ Ratings & Comments
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| POST | `/api/v1/rate` | ✅ | امتیاز به پزشک (۱-۵) |
|
||||
| GET | `/api/v1/rate/{doctorUuid}` | Public | میانگین امتیاز پزشک |
|
||||
| POST | `/api/v1/comment` | ✅ | ثبت نظر |
|
||||
| GET | `/api/v1/comments/{doctorUuid}` | Public | نظرات تأییدشده |
|
||||
| DELETE | `/api/v1/comment/{uuid}` | ✅ | حذف نظر |
|
||||
| POST | `/api/v1/like/{commentUuid}` | ✅ | لایک/آنلایک نظر |
|
||||
| GET | `/api/v1/admin/comments/pending` | ADMIN | نظرات در انتظار |
|
||||
| POST | `/api/v1/admin/comment/{uuid}/approve` | ADMIN | تأیید نظر |
|
||||
| POST | `/api/v1/admin/comment/{uuid}/reject` | ADMIN | رد نظر |
|
||||
|
||||
---
|
||||
|
||||
### 🤝 Representations (نمایندگان)
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| POST | `/api/v1/representation` | ADMIN | ایجاد نماینده |
|
||||
| GET | `/api/v1/representation/{uuid}` | ✅ | جزئیات نماینده |
|
||||
| PATCH | `/api/v1/representation/{uuid}` | ✅ | ویرایش |
|
||||
| DELETE | `/api/v1/representation/{uuid}` | ADMIN | حذف |
|
||||
| GET | `/api/v1/representation/{uuid}/dashboard/monthly` | ✅ | آمار ماهانه (شمسی) |
|
||||
| GET | `/api/v1/representation/{uuid}/dashboard/yearly` | ✅ | آمار سالانه |
|
||||
|
||||
---
|
||||
|
||||
### 🔐 Secretaries (منشیها)
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| POST | `/api/v1/secretary` | ✅ | ایجاد منشی |
|
||||
| GET | `/api/v1/secretary/{uuid}` | ✅ | جزئیات |
|
||||
| PATCH | `/api/v1/secretary/{uuid}` | ✅ | ویرایش دسترسیها |
|
||||
| DELETE | `/api/v1/secretary/{uuid}` | ✅ | حذف |
|
||||
| GET | `/api/v1/secretaries/{doctorUuid}` | ✅ | لیست منشیهای پزشک |
|
||||
|
||||
---
|
||||
|
||||
### 📱 SMS
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/admin/sms/templates` | ADMIN | لیست قالبها |
|
||||
| POST | `/api/v1/sms/template` | ADMIN | ایجاد قالب |
|
||||
| PATCH | `/api/v1/sms/template/{uuid}` | ADMIN | ویرایش قالب |
|
||||
| POST | `/api/v1/sms/template/{uuid}/submit` | ADMIN | ارسال برای تأیید |
|
||||
| POST | `/api/v1/admin/sms/template/{uuid}/approve` | ADMIN | تأیید قالب |
|
||||
| POST | `/api/v1/admin/sms/template/{uuid}/reject` | ADMIN | رد قالب |
|
||||
| POST | `/api/v1/sms/send` | ADMIN | ارسال پیامک مستقیم |
|
||||
| POST | `/api/v1/sms/send-template` | ADMIN | ارسال با قالب |
|
||||
|
||||
---
|
||||
|
||||
### 🗂 Categories
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/categorys/state` | Public | لیست استانها |
|
||||
| GET | `/api/v1/categorys/city` | Public | لیست شهرها (`?state_id=X`) |
|
||||
| GET | `/api/v1/categorys/specially_doctor` | Public | تخصصهای پزشکی |
|
||||
| GET | `/api/v1/categorys/doctor_services` | Public | خدمات پزشکی |
|
||||
| GET | `/api/v1/categorys/insurance_type` | Public | انواع بیمه پایه |
|
||||
| GET | `/api/v1/categorys/supplementary_insurance` | Public | بیمه تکمیلی |
|
||||
| GET | `/api/v1/categorys/tag` | Public | تگهای بلاگ |
|
||||
| POST | `/api/v1/category` | ADMIN | ایجاد دستهبندی |
|
||||
| PATCH | `/api/v1/category/{id}` | ADMIN | ویرایش |
|
||||
| DELETE | `/api/v1/category/{id}` | ADMIN | حذف |
|
||||
|
||||
---
|
||||
|
||||
### 📝 Blog
|
||||
|
||||
| Method | Path | Auth | توضیح |
|
||||
|--------|------|------|-------|
|
||||
| GET | `/api/v1/blogs` | Public | لیست مقالات منتشرشده |
|
||||
| GET | `/api/v1/blog/{slug}` | Public | مقاله با slug یا uuid |
|
||||
| POST | `/api/v1/blog` | ADMIN | ایجاد مقاله |
|
||||
| PATCH | `/api/v1/blog/{uuid}` | ADMIN | ویرایش |
|
||||
| DELETE | `/api/v1/blog/{uuid}` | ADMIN | حذف |
|
||||
| POST | `/file/upload/clinic_pro/blog/field_image` | ADMIN | آپلود تصویر مقاله |
|
||||
|
||||
---
|
||||
|
||||
### ❤️ Health
|
||||
|
||||
| Method | Path | توضیح |
|
||||
|--------|------|-------|
|
||||
| GET | `/health` | بررسی وضعیت DB و Redis |
|
||||
|
||||
---
|
||||
|
||||
## ۸. امنیت و احراز هویت
|
||||
|
||||
### جریان احراز هویت
|
||||
|
||||
```
|
||||
[Client] → POST /api/v1/user/login
|
||||
{ mobile_number, password }
|
||||
|
||||
↓ PasswordAuthenticator
|
||||
|
||||
[Symfony] → Rate Limit check (IP)
|
||||
→ findByMobile()
|
||||
→ verify password_hash
|
||||
→ check isStaff() (ROLE_ADMIN or ROLE_DOCTOR or ROLE_CLINIC)
|
||||
|
||||
↓ موفق
|
||||
|
||||
[Response] → {
|
||||
access_token: "eyJ...", // ← JWT، عمر: 1 ساعت
|
||||
refresh_token: "8e75...", // ← در DB کش، عمر: 30 روز
|
||||
expires_in: 3600
|
||||
}
|
||||
```
|
||||
|
||||
### JWT Token Payload
|
||||
```json
|
||||
{
|
||||
"iat": 1781031215,
|
||||
"exp": 1781034815,
|
||||
"roles": ["ROLE_ADMIN", "ROLE_USER"],
|
||||
"username": "09120671713"
|
||||
}
|
||||
```
|
||||
|
||||
### استفاده از Token
|
||||
```
|
||||
Authorization: Bearer eyJ...
|
||||
```
|
||||
|
||||
### Refresh Token
|
||||
```
|
||||
POST /oauth/token/refresh
|
||||
{ "refresh_token": "8e75..." }
|
||||
```
|
||||
|
||||
### Firewalls
|
||||
|
||||
```
|
||||
dev → مسیرهای profiler/assets (no security)
|
||||
health → /health (no security)
|
||||
public_endpoints → مسیرهای عمومی API (no security)
|
||||
payment_callback → callback درگاه (no security)
|
||||
api → ^/(api|oauth)/ — JWT authenticator
|
||||
```
|
||||
|
||||
### نقشها و دسترسیها
|
||||
|
||||
| نقش | دسترسی |
|
||||
|-----|--------|
|
||||
| `ROLE_USER` | کاربر عادی — رزرو نوبت، پرداخت |
|
||||
| `ROLE_DOCTOR` | پزشک — مدیریت پروفایل و نوبتها |
|
||||
| `ROLE_CLINIC` | مدیر کلینیک |
|
||||
| `ROLE_REPRESENTATION` | نماینده — آمار و کیف پول |
|
||||
| `ROLE_SECRETARY` | منشی — بر اساس permissions JSON |
|
||||
| `ROLE_ADMIN` | ادمین کامل — تمام endpointها |
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```yaml
|
||||
# config/packages/rate_limiter.yaml
|
||||
login: 5 تلاش در دقیقه (per IP)
|
||||
send_code: 3 درخواست در 5 دقیقه (per IP)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۹. پنل ادمین React
|
||||
|
||||
### آدرس: `https://clinic-pro.ddev.site/admin`
|
||||
|
||||
### نحوه کار
|
||||
|
||||
```
|
||||
[Browser] GET /admin/**
|
||||
↓
|
||||
[Symfony] AdminController::index()
|
||||
↓
|
||||
[Twig] templates/admin/index.html.twig
|
||||
↓ (HTML shell + Webpack assets)
|
||||
[React] mounts در #admin-root
|
||||
↓
|
||||
[React Router] مسیریابی client-side
|
||||
```
|
||||
|
||||
### مسیرهای React
|
||||
|
||||
| مسیر | صفحه | Auth |
|
||||
|------|------|------|
|
||||
| `/admin/login` | LoginPage | عمومی |
|
||||
| `/admin/dashboard` | DashboardPage | ✅ |
|
||||
| `/admin/users` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/doctors` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/clinics` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/appointments` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/payments` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/settlements` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/comments` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/ratings` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/sms` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/categories` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/blogs` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/representations` | *(در حال توسعه)* | ✅ |
|
||||
| `/admin/secretaries` | *(در حال توسعه)* | ✅ |
|
||||
|
||||
### Auth Guard
|
||||
|
||||
```typescript
|
||||
// اگر کاربر لاگین نباشد → redirect به /admin/login
|
||||
// اگر کاربر لاگین باشد و /admin/login باز کند → redirect به /admin/dashboard
|
||||
```
|
||||
|
||||
### JWT ذخیرهسازی
|
||||
|
||||
```typescript
|
||||
// Zustand + localStorage (با persist middleware)
|
||||
// کلید: 'clinicpro-auth'
|
||||
{
|
||||
token: string | null, // access_token
|
||||
refreshToken: string | null,
|
||||
isAuthenticated: boolean
|
||||
}
|
||||
```
|
||||
|
||||
### طراحی (Design System)
|
||||
|
||||
```css
|
||||
/* رنگ اصلی */
|
||||
--color-primary-500: #8b5cf6; /* بنفش */
|
||||
--color-bg-sidebar: #0f172a; /* dark navy */
|
||||
--color-bg-body: #f1f5f9; /* خاکستری روشن */
|
||||
|
||||
/* فونت */
|
||||
font-family: "Vazirmatn", "Inter", sans-serif;
|
||||
direction: rtl;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۱۰. Frontend Build
|
||||
|
||||
### دستورات npm
|
||||
|
||||
```bash
|
||||
npm run dev # build یکبار (dev)
|
||||
npm run watch # build + watch
|
||||
npm run build # build production (minified + hashed)
|
||||
npm run dev-server # webpack dev server (HMR)
|
||||
```
|
||||
|
||||
### فایلهای خروجی
|
||||
|
||||
```
|
||||
public/build/
|
||||
├── runtime.js ← webpack runtime
|
||||
├── admin.js ← React Admin bundle
|
||||
├── admin.css ← Tailwind CSS
|
||||
├── app.js ← Symfony main bundle
|
||||
├── vendors-*.js ← کتابخانههای مشترک
|
||||
└── manifest.json ← نقشه فایلها
|
||||
```
|
||||
|
||||
### تنظیمات TypeScript (`tsconfig.json`)
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"baseUrl": ".",
|
||||
"paths": { "@/*": ["assets/admin/*"] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### تنظیمات PostCSS (`postcss.config.js`)
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
plugins: { '@tailwindcss/postcss': {} }
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۱۱. دستورات Console
|
||||
|
||||
### دستور موجود
|
||||
|
||||
```bash
|
||||
# لغو خودکار نوبتهای منقضیشده
|
||||
ddev exec php bin/console app:cancel-expired-appointments
|
||||
|
||||
# توضیح: نوبتهایی که slot_start آنها گذشته و هنوز pending هستند
|
||||
# را به وضعیت auto_cancel_unpaid تغییر میدهد
|
||||
# اجرا: از طریق cron job (مثلاً هر ۱۵ دقیقه)
|
||||
```
|
||||
|
||||
### دستورات Symfony مفید
|
||||
|
||||
```bash
|
||||
# مشاهده همه routeها
|
||||
ddev exec php bin/console debug:router
|
||||
|
||||
# پاک کردن کش
|
||||
ddev exec php bin/console cache:clear
|
||||
|
||||
# اجرای migrations
|
||||
ddev exec php bin/console doctrine:migrations:migrate
|
||||
|
||||
# هش کردن پسورد
|
||||
ddev exec php bin/console security:hash-password "your_password"
|
||||
|
||||
# تولید JWT key
|
||||
ddev exec php bin/console lexik:jwt:generate-keypair
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۱۲. Migrations
|
||||
|
||||
**تعداد:** ۱۶ migration
|
||||
**آخرین نسخه:** `Version20260609140423`
|
||||
|
||||
```bash
|
||||
# مشاهده وضعیت
|
||||
ddev exec php bin/console doctrine:migrations:status
|
||||
|
||||
# اجرای migrations جدید
|
||||
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
|
||||
|
||||
# ساخت migration جدید
|
||||
ddev exec php bin/console doctrine:migrations:diff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۱۳. سرویسهای خارجی
|
||||
|
||||
### درگاههای پرداخت
|
||||
|
||||
| درگاه | Provider | متغیرها |
|
||||
|-------|----------|---------|
|
||||
| بانک ملت | `MellatGateway` | `MELLAT_TERMINAL_ID`, `MELLAT_USERNAME`, `MELLAT_PASSWORD` |
|
||||
| سامان (SEP) | `SepGateway` | `SEP_TERMINAL_ID` |
|
||||
|
||||
**IPهای مجاز callback:** در `ALLOWED_FRONTEND_HOSTS` تنظیم میشود.
|
||||
|
||||
---
|
||||
|
||||
### SMS Providers
|
||||
|
||||
| ارائهدهنده | Provider Class | انتخاب |
|
||||
|------------|---------------|--------|
|
||||
| کاوهنگار | `KavehNegarProvider` | `SMS_PROVIDER=kavenegar` |
|
||||
| رنگینه | `RanginehProvider` | `SMS_PROVIDER=rangineh` |
|
||||
|
||||
---
|
||||
|
||||
### Redis
|
||||
- صف پیام (Symfony Messenger)
|
||||
- کش OTP codes
|
||||
- کش Refresh Tokens
|
||||
- Rate limiter storage
|
||||
|
||||
---
|
||||
|
||||
### JWT Keys
|
||||
```
|
||||
config/jwt/private.pem ← کلید خصوصی (در .gitignore)
|
||||
config/jwt/public.pem ← کلید عمومی (در .gitignore)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## خلاصه آماری
|
||||
|
||||
| معیار | تعداد |
|
||||
|-------|-------|
|
||||
| Domain modules | ۱۵ |
|
||||
| PHP Controllers | ۱۷ |
|
||||
| API Endpoints | ۱۳۰+ |
|
||||
| Doctrine Entities | ۲۲ |
|
||||
| Database Tables | ۳۰ |
|
||||
| Migrations | ۱۶ |
|
||||
| React Pages | ۲ (پیادهسازیشده) + ۱۳ (در حال توسعه) |
|
||||
| npm packages | ۳۴ |
|
||||
| composer packages | ۲۸ |
|
||||
Reference in New Issue
Block a user