Files
clinicpro/README.MD
T
hamed e9075e8c92 Add comprehensive project documentation for ClinicPro in CLAUDE.md and README.md
- Introduced CLAUDE.md for internal guidance on project structure, commands, and architecture.
- Created README.md with detailed project overview, technology stack, directory structure, setup instructions, API endpoints, authentication flow, and external services.
2026-06-10 11:12:15 +03:30

1036 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
- امتیاز و نظرات پزشکان
- بلاگ
- مستندات API تعاملی (Swagger UI) — محافظت‌شده با HTTP Basic Auth
---
## ۲. تکنولوژی 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 | MariaDB 11.8 |
| API Docs | NelmioApiDocBundle v5 + swagger-php v6 |
| 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/ ← ۲۲ صفحه پیاده‌سازی‌شده
│ │ ├── 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
│ │ ├── nelmio_api_doc.yaml ← Swagger config
│ │ ├── rate_limiter.yaml
│ │ └── webpack_encore.yaml
│ └── routes/
│ ├── security.yaml
│ └── nelmio_api_doc.yaml
├── migrations/ ← 17 Doctrine migrations
├── public/
│ ├── index.php
│ ├── build/ ← Webpack output
│ └── bundles/nelmioapidoc/ ← Swagger UI assets (local)
├── src/
│ ├── Admin/Controller/ ← AdminApiController + 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 | JWT auth |
| API | https://clinic-pro.ddev.site/api/v1 | REST API |
| Swagger UI | https://clinic-pro.ddev.site/api/doc | HTTP Basic Auth |
| Health Check | https://clinic-pro.ddev.site/health | عمومی |
### اطلاعات ادمین پیش‌فرض
| فیلد | مقدار |
|------|-------|
| موبایل | `09120671713` |
| رمز عبور | `admin1234` |
| نقش | `ROLE_ADMIN` |
### اطلاعات ورود به Swagger UI
| فیلد | مقدار پیش‌فرض |
|------|--------------|
| Username | `admin` |
| Password | `clinic-pro-docs` |
> برای تغییر رمز: `ddev exec php -r "echo password_hash('رمز-جدید', PASSWORD_BCRYPT) . PHP_EOL;"` — hash را در `.env` در `API_DOC_PASSWORD` قرار دهید.
---
## ۵. متغیرهای محیطی
فایل `.env` — کلیدها (مقادیر حساس در `.env.local` تنظیم می‌شوند):
```env
APP_ENV=dev|prod
APP_SECRET= # کلید امنیتی Symfony
DEFAULT_URI= # آدرس پایه سایت (مثلاً https://clinic-pro.ddev.site)
DATABASE_URL= # DSN پایگاه داده MariaDB
JWT_SECRET_KEY= # مسیر کلید خصوصی JWT
JWT_PUBLIC_KEY= # مسیر کلید عمومی JWT
JWT_PASSPHRASE= # رمز کلید JWT
CORS_ALLOW_ORIGIN= # آدرس‌های مجاز CORS (regex)
MESSENGER_TRANSPORT_DSN= # DSN صف پیام (Redis)
REDIS_URL= # آدرس Redis
REFRESH_TOKEN_TTL=2592000 # عمر refresh token (ثانیه) = ۳۰ روز
OTP_TTL=1200 # عمر کد OTP (ثانیه) = ۲۰ دقیقه
# SMS
KAVENEGAR_API_KEY=
KAVENEGAR_SENDER=
RANGINEH_API_KEY=
RANGINEH_SENDER=
SMS_PROVIDER=kavenegar|rangineh # ارائه‌دهنده فعال
# File Upload
MAX_FILE_SIZE_BYTES=5242880 # حداکثر حجم فایل (۵ مگابایت)
UPLOAD_DIR= # مسیر ذخیره فایل‌ها
# Payment
ALLOWED_FRONTEND_HOSTS= # هاست‌های مجاز برای redirect پرداخت
MELLAT_TERMINAL_ID=
MELLAT_USERNAME=
MELLAT_PASSWORD=
SEP_TERMINAL_ID=
APP_BASE_URL= # آدرس پایه برای callback پرداخت
# API Documentation (Swagger UI)
API_DOC_USERNAME=admin # نام کاربری ورود به /api/doc
API_DOC_PASSWORD= # bcrypt hash رمز عبور
```
---
## ۶. پایگاه داده — موجودیت‌ها
### جداول پایگاه داده
| جدول | 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 (bundle='city')
state_id INT nullable → categories (bundle='state')
representation_id INT nullable
images_clinic JSON nullable
clinic_logo JSON nullable
```
---
### Representation (representations)
```
id INT PK
uuid VARCHAR(36) UNIQUE
full_name VARCHAR(255)
mobile_number VARCHAR(20)
city_id INT nullable → categories (bundle='city') ← ID شهر (نه نام)
wallet_balance INT default:0
commission_rate FLOAT default:10.0
is_active BOOL default:true
created_at INT (unix timestamp)
updated_at INT (unix timestamp)
```
> **توجه:** `city_id` یک FK عددی به جدول `categories` (bundle='city') است. نام شهر از طریق JOIN در API برگردانده می‌شود.
---
### 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.id)
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`
> مستندات کامل تعاملی: **https://clinic-pro.ddev.site/api/doc** (نیاز به HTTP Basic Auth)
---
### 🔐 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
}
```
---
### 🩺 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 | 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}` | ✅ | لایک/آنلایک نظر |
---
### 🤝 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/{bundle}` | Public | لیست دسته‌بندی (`?state_id=X`) |
| POST | `/api/v1/category` | ADMIN | ایجاد دسته‌بندی |
| PATCH | `/api/v1/category/{id}` | ADMIN | ویرایش |
| DELETE | `/api/v1/category/{id}` | ADMIN | حذف |
**مقادیر `{bundle}`:** `state` | `city` | `specially_doctor` | `doctor_services` | `insurance_type` | `supplementary_insurance` | `tag`
---
### 📝 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 | آپلود تصویر مقاله |
---
### 🖥 Admin API (`/api/v1/admin/`)
همه endpoint‌های ادمین نیاز به `ROLE_ADMIN` دارند:
| Method | Path | توضیح |
|--------|------|-------|
| GET | `/api/v1/admin/users` | لیست کاربران (`?search=`) |
| GET | `/api/v1/admin/appointments` | لیست نوبت‌ها |
| GET | `/api/v1/admin/payments` | لیست پرداخت‌ها |
| GET | `/api/v1/admin/representations` | لیست نمایندگان (`?city_id=`) |
| GET | `/api/v1/admin/secretaries` | لیست منشی‌ها |
| GET | `/api/v1/admin/rates` | لیست امتیازها |
| GET | `/api/v1/admin/comments` | لیست نظرات |
| GET | `/api/v1/admin/sms/logs` | لاگ پیامک‌ها |
| GET | `/api/v1/admin/settlements` | لیست تسویه‌حساب‌ها |
| GET | `/api/v1/admin/sms/sample-templates` | قالب‌های نمونه پیامک |
| GET | `/api/v1/admin/dashboard/stats` | آمار کلی داشبورد |
| GET | `/api/v1/admin/dashboard/recent` | فعالیت‌های اخیر |
---
### ❤️ 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()
↓ موفق
[Response] → {
access_token: "eyJ...", // JWT — عمر: ۱ ساعت
refresh_token: "8e75...", // در DB کش — عمر: ۳۰ روز
expires_in: 3600
}
```
### JWT Token Payload
```json
{
"iat": 1781031215,
"exp": 1781034815,
"roles": ["ROLE_ADMIN", "ROLE_USER"],
"username": "09120671713"
}
```
### استفاده از Token
```
Authorization: Bearer eyJ...
```
### Firewalls
```
dev → ^/(_profiler|_wdt|assets|build)/ — no security
health → ^/health$ — no security
api_doc → ^/api/doc — HTTP Basic Auth (InMemoryUser)
public_endpoints → مسیرهای عمومی API — no security
payment_callback → callback درگاه پرداخت — no security
api → ^/(api|oauth)/ — JWT authenticator
```
### محافظت از Swagger UI
مسیر `/api/doc` از طریق یک firewall جداگانه با **HTTP Basic Authentication** محافظت می‌شود:
```yaml
# config/packages/security.yaml
api_doc:
pattern: ^/api/doc
http_basic:
realm: "ClinicPro API Documentation"
provider: api_doc_provider
```
اطلاعات ورود از متغیرهای محیطی `API_DOC_USERNAME` و `API_DOC_PASSWORD` (bcrypt hash) خوانده می‌شود.
### نقش‌ها و دسترسی‌ها
| نقش | دسترسی |
|-----|--------|
| `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 (پیاده‌سازی‌شده)
| مسیر | صفحه | توضیح |
|------|------|-------|
| `/admin/login` | LoginPage | ورود با JWT |
| `/admin/dashboard` | DashboardPage | آمار واقعی از API |
| `/admin/users` | UsersPage | لیست کاربران |
| `/admin/users/:uuid` | UserDetailPage | جزئیات کاربر |
| `/admin/doctors` | DoctorsPage | لیست پزشکان |
| `/admin/doctors/:uuid` | DoctorDetailPage | جزئیات پزشک |
| `/admin/clinics` | ClinicsPage | لیست کلینیک‌ها |
| `/admin/clinics/:uuid` | ClinicDetailPage | جزئیات کلینیک |
| `/admin/appointments` | AppointmentsPage | لیست نوبت‌ها |
| `/admin/appointments/:uuid` | AppointmentDetailPage | جزئیات نوبت |
| `/admin/payments` | PaymentsPage | لیست پرداخت‌ها |
| `/admin/payments/:uuid` | PaymentDetailPage | جزئیات پرداخت |
| `/admin/settlements` | SettlementsPage | لیست تسویه‌حساب‌ها |
| `/admin/representations` | RepresentationsPage | لیست نمایندگان (فیلتر شهر) |
| `/admin/representations/:uuid` | RepresentationDetailPage | جزئیات نماینده |
| `/admin/comments` | CommentsPage | مدیریت نظرات |
| `/admin/ratings` | RatingsPage | لیست امتیازها |
| `/admin/sms` | SmsPage | مدیریت پیامک |
| `/admin/categories` | CategoriesPage | مدیریت دسته‌بندی‌ها |
| `/admin/blogs` | BlogsPage | لیست مقالات |
| `/admin/blogs/new` | BlogFormPage | ایجاد مقاله |
| `/admin/blogs/:uuid/edit` | BlogFormPage | ویرایش مقاله |
| `/admin/secretaries` | SecretariesPage | مدیریت منشی‌ها |
### 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
ddev exec yarn dev # build یک‌بار (dev)
ddev exec yarn watch # build + watch
ddev exec yarn build # build production (minified + hashed)
```
> **توجه:** خطای `lightningcss.linux-arm64-gnu.node` در محیط ddev از پیش وجود دارد و JS/TS compilation را مسدود نمی‌کند.
### فایل‌های خروجی
```
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/*"] }
}
}
```
---
## ۱۱. دستورات Console
### دستورات کاربردی
```bash
# لغو خودکار نوبت‌های منقضی‌شده
ddev exec php bin/console app:cancel-expired-appointments
# مشاهده همه route‌ها
ddev exec php bin/console debug:router | grep api
# پاک کردن کش
ddev exec php bin/console cache:clear
# اجرای migrations
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
# ساخت migration بعد از تغییر entity
ddev exec php bin/console doctrine:migrations:diff --no-interaction
# هش کردن پسورد
ddev exec php bin/console security:hash-password "رمز-جدید"
# تولید JWT key
ddev exec php bin/console lexik:jwt:generate-keypair
# بررسی صف پیام
ddev exec php bin/console messenger:consume async
# خروجی OpenAPI/Swagger
ddev exec php bin/console nelmio:apidoc:dump
```
---
## ۱۲. Migrations
**تعداد:** ۱۷ migration
```bash
# مشاهده وضعیت
ddev exec php bin/console doctrine:migrations:status
# اجرای migrations جدید
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
# ساخت migration جدید بعد از تغییر entity
ddev exec php bin/console doctrine:migrations:diff
```
---
## ۱۳. سرویس‌های خارجی
### درگاه‌های پرداخت
| درگاه | Provider | متغیرها |
|-------|----------|---------|
| بانک ملت | `MellatGateway` | `MELLAT_TERMINAL_ID`, `MELLAT_USERNAME`, `MELLAT_PASSWORD` |
| سامان (SEP) | `SepGateway` | `SEP_TERMINAL_ID` |
---
### SMS Providers
| ارائه‌دهنده | Provider Class | انتخاب |
|------------|---------------|--------|
| کاوه‌نگار | `KavehNegarProvider` | `SMS_PROVIDER=kavenegar` |
| رنگینه | `RanginehProvider` | `SMS_PROVIDER=rangineh` |
---
### Redis
- صف پیام (Symfony Messenger)
- کش کدهای OTP
- کش Refresh Tokens
- Rate limiter storage
---
### JWT Keys
```
config/jwt/private.pem ← کلید خصوصی (در .gitignore)
config/jwt/public.pem ← کلید عمومی (در .gitignore)
```
---
## خلاصه آماری
| معیار | تعداد |
|-------|-------|
| Domain modules | ۱۵ |
| PHP Controllers | ۱۷ |
| API Endpoints | ۹۷ (مستندسازی‌شده در Swagger) |
| Doctrine Entities | ۲۲ |
| Database Tables | ۳۰ |
| Migrations | ۱۷ |
| React Pages | ۲۳ مسیر (کاملاً پیاده‌سازی‌شده) |
| OpenAPI Tags | ۱۱ گروه |
| npm packages | ۳۴ |
| composer packages | ۲۸ |