---
title: کلینیک پرو — مستند جامع فنی و API
version: 2.0.0
status: پیشنویس
---
# کلینیک پرو — مستند جامع فنی و API
> **نسخه:** 2.0.0 | **وضعیت:** پیشنویس — در حال بررسی | **سال:** ۱۴۰۴
>
> **Base URL:** `https://back-dev.clinic-pro.ir`
>
> **احراز هویت:** `Authorization: Bearer {access_token}` | **Content-Type:** `application/json`
>
> **علامت 🆕** = این endpoint دارای Response Body واقعی از سرور است.
---
## فهرست کلی
**بخش اول — مستند محصول (PRD)**
1. [معرفی محصول](#۱-معرفی-محصول)
2. [مدل داده و موجودیتها](#۲-مدل-داده-و-موجودیتها)
3. [مشخصات API (Task-based)](#۳-مشخصات-api)
4. [سیستم حساب و صف پیامک](#۴-سیستم-حساب-و-صف-پیامک)
5. [فهرست مشکلات](#۵-فهرست-مشکلات-شناساییشده-و-اصلاحات-لازم)
6. [پیوست](#۶-پیوست)
**بخش دوم — مستند کامل API (۹۹ Endpoint)**
- [1. احراز هویت (Authentication)](#1-احراز-هویت-(authentication))
- [2. کاربر (User)](#2-کاربر-(user))
- [3. پروفایل بیمار (User Profile)](#3-پروفایل-بیمار-(user-profile))
- [4. دکتر (Doctor)](#4-دکتر-(doctor))
- [5. آدرس دکتر (Doctor Address)](#5-آدرس-دکتر-(doctor-address))
- [6. کلینیک (Clinic)](#6-کلینیک-(clinic))
- [7. نماینده (Agent / Representation)](#7-نماینده-(agent-/-representation))
- [8. دستهبندیها (Categories)](#8-دستهبندیها-(categories))
- [9. بیمه دکتر (Doctor Insurance)](#9-بیمه-دکتر-(doctor-insurance))
- [10. تنظیمات نوبت — برنامه هفتگی](#10-تنظیمات-نوبت-—-برنامه-هفتگی)
- [11. تنظیمات نوبت — Date Override](#11-تنظیمات-نوبت-—-date-override)
- [12. تنظیمات نوبت — تعطیلات](#12-تنظیمات-نوبت-—-تعطیلات)
- [13. نوبتدهی (Appointment)](#13-نوبتدهی-(appointment))
- [14. منشی (Secretary)](#14-منشی-(secretary))
- [15. پرداخت (Payment)](#15-پرداخت-(payment))
- [16. وبلاگ (Blog)](#16-وبلاگ-(blog))
---
# بخش اول — مستند محصول (PRD)
# ۱. معرفی محصول
کلینیک پرو یک سیستم جامع مدیریت کلینیک است که برای خدمترسانی به دکترهای مستقل، کلینیکهای چند پزشکی، نمایندگان شهری، منشیها و بیماران طراحی شده است. این سیستم ثبتنام کاربران، احراز هویت، نوبتدهی آنلاین، مدیریت اشتراک، ارسال پیامک و جریانهای مالی شامل پیگیری کمیسیون را پوشش میدهد.
## ۱.۱ نقشهای سیستم
| **نقش** | **توضیحات** |
| ------------------ | ----------------------------------------------------------------- |
| Administrator | ادمین ارشد — مدیریت تنظیمات پلتفرم، تعطیلات، پلنها و نرخ کمیسیون |
| admin | ادمین داخلی با دسترسی بالا |
| clinic | صاحب کلینیک — مدیریت پروفایل کلینیک، دکترها و نوبتها |
| doctor | پزشک مستقل یا وابسته به کلینیک |
| doctor_s_secretary | منشی اختصاصی دکتر (دسترسیها از طریق JSON مدیریت میشود) |
| patient | کاربر نهایی که نوبت رزرو میکند |
| representation | نماینده شهری که روی دامنه خود فعالیت میکند |
## ۱.۲ فلوهای عملیاتی اصلی
### ثبتنام دکتر — مستقل
- دکتر با شماره موبایل در سیستم ثبتنام میکند
- سیستم حساب کاربری با نقش doctor ایجاد میکند
- دکتر پروفایل را تکمیل و پلن را سابسکرایب میکند
### ثبتنام دکتر — از طریق کلینیک
- صاحب کلینیک دکتر را با شماره موبایل اضافه میکند
- پیامک با لینک تأیید/رد برای دکتر ارسال میشود
- در صورت رد: هیچ اقدامی انجام نمیشود
- در صورت تأیید: پیامک با لینک دانلود نرمافزار ارسال میشود
### ثبتنام دکتر — از طریق نماینده
- نماینده شماره موبایل دکتر و اطلاعات مربوطه را وارد میکند
- پیامک خوشآمدگویی با لینک دانلود نرمافزار برای دکتر ارسال میشود
- در صورت سابسکرایب پلن توسط دکتر: کمیسیون به کیف پول نماینده واریز میشود
## ۱.۳ پلنهای اشتراک
| **ویژگی** | **پلن بیسیک (رایگان)** | **پلن پیشرفته** |
| --------------------- | ---------------------- | ------------------- |
| تعداد منشی فعال | ۱ منشی | ۳ منشی |
| نوبتدهی آنلاین | ✓ (با کمیسیون سایت) | ✓ (با کمیسیون سایت) |
| نوبتدهی آفلاین | ✗ | ✓ |
| پشتیبانگیری (Backup) | ✗ | ✓ |
| نوبت توسط منشی | بدون کمیسیون سایت | بدون کمیسیون سایت |
*نکته: تعریف پلنها (ویژگیها، قیمت) باید از پنل ادمین قابل تنظیم باشد. مبلغ کمیسیون به ازای هر نوبت آنلاین نیز باید قابل تنظیم باشد (مثلاً ۱۰،۰۰۰ تومان به ازای هر نوبت).*
## ۱.۴ سیستم پیامک
هر دکتر یا کلینیک باید یک حساب پیامک مستقل داشته باشد.
- دکتر یا کلینیک حساب پیامک خود را با تعداد مشخصی پیامک شارژ میکند (مثلاً ۱۰۰۰ پیامک)
- نرمافزار لوکال (Tauri) یک جاب اجرا میکند که یک روز قبل از نوبت برای بیماران پیامک یادآوری ارسال میکند
- این پیامکها در صف ارسال قرار میگیرند
- به ازای هر پیامک ارسالشده، موجودی از حساب دکتر یا کلینیک کسر میشود
# ۲. مدل داده و موجودیتها
## ۲.۱ کاربر (User)
موجودیت مرکزی سیستم. تمام نقشها از این ساختار استفاده میکنند.
**⚠ مشکل شناساییشده: جدول کاربران به درستی ایجاد نشده است. باید بر اساس فیلدهای زیر بازسازی شود.**
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------- | ----------------- | ------------------------------------------------------------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی — افزایشی خودکار | بله |
| uuid | UUID | شناسه یکتای جهانی | بله |
| uid | Integer (FK→User) | شناسه کاربر — ارجاع به خود جدول | بله |
| mobile_number | String (unique) | شماره موبایل — به عنوان نام کاربری استفاده میشود | بله |
| password | String (hashed) | رمز عبور — هششده با Bcrypt | بله |
| realname | String | نام و نام خانوادگی کامل | بله |
| picture | String (URL) | آدرس تصویر پروفایل | اختیاری |
| roles | Array
| نقشهای اختصاصیافته: administrator, admin, clinic, doctor, doctor_s_secretary, patient, representation | بله |
| status | Boolean | وضعیت حساب: فعال / غیرفعال | بله |
| created | Timestamp | زمان ایجاد رکورد | بله |
| changed | Timestamp | آخرین زمان ویرایش | بله |
**⚠ مشکل شناساییشده: جدول نقشها (Roles) به درستی ایجاد نشده است. نقشها باید به صورت Enum تعریف و به کاربر متصل شوند.**
## ۲.۲ انواع دستهبندی (Category Types)
**⚠ مشکل شناساییشده (Task-08): شهرها و استانها به درستی ست نشدهاند. تمام دستهبندیها باید کاملاً تعریف شوند.**
### ۲.۲.۱ تگ (Tag)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | ------------ | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| label | String | نام تگ | بله |
| status | Boolean | فعال/غیرفعال | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۲.۲ استان (State)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | ------------ | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| label | String | نام استان | بله |
| status | Boolean | فعال/غیرفعال | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۲.۳ شهر (City)
**⚠ اصلاح شده: فیلد parent (ارجاع به استان) و سایر فیلدها باید کاملاً پیکربندی شوند.**
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ----------------- | --------------------- | ------------------------------ | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| label | String | نام شهر | بله |
| parent | Integer (FK→state.id) | ارجاع به استان مربوطه — الزامی | بله |
| status | Boolean | فعال/غیرفعال | بله |
| domain | String | دامنه نماینده این شهر | اختیاری |
| representation | Integer (FK→rep.id) | نماینده مرتبط با شهر | اختیاری |
| contactphone | String | شماره تماس | اختیاری |
| email | String | ایمیل تماس | اختیاری |
| description | Text | توضیحات شهر | اختیاری |
| title | String | عنوان صفحه شهر | اختیاری |
| keywords | String | کلمات کلیدی SEO | اختیاری |
| footerDescription | Text | متن فوتر سایت نماینده | اختیاری |
| footerDisclaimer | Text | سلب مسئولیت فوتر | اختیاری |
| socialMedia | JSON | لینکهای شبکههای اجتماعی | اختیاری |
| weight | Integer | وزن مرتبسازی | اختیاری |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۲.۴ بیمه پایه (Basic Insurance)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | ------------ | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| label | String | نام بیمه | بله |
| logo | String (URL) | لوگوی بیمه | اختیاری |
| status | Boolean | فعال/غیرفعال | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۲.۵ بیمه مکمل (Supplementary Insurance)
ساختار یکسان با بیمه پایه.
### ۲.۲.۶ تخصص دکتر (Doctor Specialty)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ------------------------- | ----------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| label | String | نام تخصص | بله |
| parent | Integer (FK→specialty.id) | تخصص والد (برای ساختار درختی) | اختیاری |
| status | Boolean | فعال/غیرفعال | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۲.۷ خدمات دکتر (Doctor Services)
**⚠ اصلاح شده (Task-05): در تمام پاسخهای API باید هم id و هم label (نام) ارسال شود.**
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | --------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی — الزامی در تمام پاسخهای API | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| label | String | نام خدمت — الزامی در تمام پاسخهای API | بله |
| status | Boolean | فعال/غیرفعال | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۳ دکتر (Doctor)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------------------- | ---------------------- | --------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | حساب کاربری متصل | بله |
| label / name | String | نام نمایشی دکتر | بله |
| gender | Enum | جنسیت: male / female | بله |
| degree | Enum | expert │ general │ specialist │ subspecialistplus | بله |
| doctor_id | String | شماره نظام پزشکی | بله |
| doctor_mobile_number | String | شماره موبایل دکتر | بله |
| clinic_specialty | Integer (FK→specialty) | تخصص اصلی دکتر | بله |
| doctor_services | Array | خدمات ارائهشده (id + label باید در پاسخها برگردد) | بله |
| state | Integer (FK→state.id) | استان محل فعالیت | بله |
| city | Integer (FK→city.id) | شهر محل فعالیت | بله |
| representation | Integer (FK→rep.id) | نماینده متصل (در صورت وجود) | اختیاری |
| active_doctor_appointment | Boolean | آیا نوبتدهی آنلاین فعال است؟ | بله |
| doctor_rate | Decimal | میانگین امتیاز | بله |
| doctor_rate_percentage | Float | درصد امتیاز | بله |
| info | Text / JSON | بیوگرافی و اطلاعات تکمیلی | اختیاری |
| activity_time | JSON | ساعات کاری | اختیاری |
| images | Array | آدرس تصاویر پروفایل | اختیاری |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۴ کلینیک (Clinic)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ---------------- | ---------------------- | ------------------------------------ | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر صاحب کلینیک | بله |
| label / name | String | نام کلینیک | بله |
| address | Text | آدرس کامل | بله |
| latitude | Decimal | عرض جغرافیایی | بله |
| longitude | Decimal | طول جغرافیایی | بله |
| telephone | String | شماره تماس | بله |
| state | Integer (FK→state.id) | استان | بله |
| city | Integer (FK→city.id) | شهر | بله |
| clinic_specialty | Array | تخصصهای کلینیک | بله |
| doctor_services | Array | خدمات (id + label الزامی در پاسخها) | بله |
| insurance | Array | بیمههای پذیرفتهشده | بله |
| doctors | Array | دکترهای عضو کلینیک | بله |
| working_days | JSON | روزهای کاری هفته | بله |
| 24_7 | Boolean | آیا شبانهروزی فعال است؟ | بله |
| logo | String (URL) | لوگوی کلینیک | بله |
| images | Array | تصاویر گالری | اختیاری |
| representation | Integer (FK→rep.id) | نماینده متصل | اختیاری |
| info | Text | درباره کلینیک | اختیاری |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۵ آدرسهای دکتر (Doctor Addresses)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ------------------- | ---------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| name | String | برچسب آدرس (مثلاً: مطب اصلی، شعبه) | بله |
| doctor | Integer (FK→doctor) | دکتر مرتبط | بله |
| address | Text | آدرس کامل | بله |
| latitude | Decimal | عرض جغرافیایی | بله |
| longitude | Decimal | طول جغرافیایی | بله |
| telephone | String | شماره تماس محل | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۶ منشی دکتر (Doctor Secretary)
محدودیت منشی فعال باید هنگام ایجاد یا فعالسازی در سمت سرور بررسی شود.
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ------------------- | ----------------------------------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| secretary | Integer (FK→user) | حساب کاربری منشی | بله |
| doctor | Integer (FK→doctor) | دکتر مرتبط | بله |
| active | Boolean | فعال/غیرفعال — پلن بیسیک: حداکثر ۱ منشی فعال؛ پلن پیشرفته: حداکثر ۳ منشی فعال | بله |
| permission | JSON | نقشه دسترسیهای دقیق منشی | بله |
| telephone | String | شماره تماس منشی | اختیاری |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۷ نماینده (Representation)
**⚠ اصلاح شده (Task-07): فیلدهای استان، شهر و شماره کارت بانکی باید به درستی تعریف شوند.**
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------------ | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | حساب کاربری نماینده | بله |
| label | String | نام نماینده | بله |
| active | Boolean | فعال/غیرفعال | بله |
| state | Integer (FK→state.id) | استان — الزامی (قبلاً وجود نداشت) | بله |
| city | Integer (FK→city.id) | شهر — الزامی (قبلاً وجود نداشت) | بله |
| address | Text | آدرس دفتر نماینده | بله |
| domain | String | زیردامنه پورتال نماینده | بله |
| bank_account | JSON Array | آرایهای از اطلاعات کارتهای بانکی. هر آیتم: { card_number, bank_name, is_default }. یکی باید is_default=true داشته باشد — الزامی (قبلاً وجود نداشت) | بله |
| commission_percent | Decimal | درصد کمیسیون از هر نوبت آنلاین | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
نمونه ساختار JSON کارتهای بانکی:
| [ { "card_number": "6037-9999-1234-5678", "bank_name": "ملت", "is_default": true }, { "card_number": "5859-3312-4455-6677", "bank_name": "صادرات", "is_default": false } ] |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
## ۲.۸ تنظیمات نوبت (Appointment Settings)
**⚠ اصلاح شده (Task-09): الگوریتم محاسبه اسلاتها باید اولویت Override را رعایت کند.**
### ۲.۸.۱ برنامه هفتگی (Weekly Schedule)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ------------------- | ----------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سازنده | بله |
| doctor_id | Integer (FK→doctor) | دکتر مرتبط | بله |
| active | Boolean | فعال/غیرفعال | بله |
| date | Timestamp | تاریخ مرجع برنامه | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۸.۲ تعطیلات (Holidays)
تعطیلات فقط توسط ادمین ثبت میشود.
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | ---------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | ادمین ثبتکننده تعطیلی | بله |
| label | String | نام / توضیح تعطیلی | بله |
| date | Timestamp | تاریخ تعطیل | بله |
| active | Boolean | فعال/غیرفعال | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۸.۳ لغو تعطیل (Date Override)
دکتر میتواند یک روز تعطیل را override کند و در آن روز کار کند. Override اولویت بالاتری از تعطیلات دارد.
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ------------------- | ------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر دکتر | بله |
| doctor_id | Integer (FK→doctor) | دکتری که Override ثبت کرده | بله |
| date | Timestamp | تاریخ مورد نظر برای Override | بله |
| setting | JSON | برنامه سفارشی برای آن روز (اسلاتها، ظرفیت و ...) | بله |
| active | Boolean | آیا این Override فعال است؟ | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۸.۴ الگوریتم محاسبه اسلاتهای خالی
اولویتبندی هنگام محاسبه اسلاتهای موجود برای یک تاریخ مشخص:
| **اولویت** | **منبع** | **رفتار سیستم** | **نتیجه** |
| -------------- | --------------- | -------------------------------------------------------------------------------------------------------- | ---------- |
| ۱ (بالاترین) | Date Override | اگر Override فعال برای این تاریخ وجود داشت → از برنامه Override استفاده شود. تعطیلی نادیده گرفته میشود. | باز |
| ۲ | Holidays | اگر تاریخ تعطیل باشد AND Override وجود نداشته باشد → روز تعطیل، بدون اسلات. | بسته |
| ۳ (پایینترین) | Weekly Schedule | اگر نه Override و نه تعطیلی → برنامه هفتگی اعمال میشود. | طبق برنامه |
## ۲.۹ نوبت (Appointment)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| -------------- | ------------------- | --------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر بیمار | بله |
| doctor_id | Integer (FK→doctor) | دکتر مربوطه | بله |
| address | Text | آدرس محل نوبت | بله |
| start_time | Timestamp | زمان شروع نوبت | بله |
| end_time | Timestamp | زمان پایان نوبت | بله |
| slot | JSON | متادیتای اسلات (شماره اسلات، مدت و ...) | بله |
| status | Enum | وضعیت نوبت — جدول زیر | بله |
| visited_at | Timestamp | زمان واقعی ویزیت | اختیاری |
| representation | Integer (FK→rep) | در صورت رزرو از طریق دامنه نماینده | اختیاری |
| info | JSON | توضیحات تکمیلی | اختیاری |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
وضعیتهای نوبت (Appointment Status):
| **waiting_for_payment** | **auto_cancel_unpaid** | **reserved** |
| ------------------------ | ----------------------- | -------------- |
| **cancelled_by_patient** | **cancelled_by_doctor** | **checked_in** |
| **waiting** | **in_progress** | **visited** |
| **no_show** | **postponed** | **completed** |
## ۲.۱۰ پرداخت (Payment Types)
### ۲.۱۰.۱ پرداخت نوبت
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ---------------- | ----------------- | ---------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | پرداختکننده | بله |
| reference_id | Integer (FK→appt) | نوبت مرتبط | بله |
| amount | Decimal | مبلغ پرداختی (تومان) | بله |
| payment_method | String | روش / درگاه پرداخت | بله |
| payment_time | Timestamp | زمان پرداخت | بله |
| ref_id | String | شماره مرجع درگاه | بله |
| card_info | JSON | اطلاعات ماسکشده کارت | بله |
| representation | Integer (FK→rep) | نماینده (در صورت پرداخت از طریق دامنه نماینده) | اختیاری |
| frontend_address | String (URL) | آدرس بازگشت پس از پرداخت | بله |
| status | Enum | pending │ received │ refund │ canceled | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۱۰.۲ پرداخت اشتراک
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ---------------- | ----------------------- | -------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر سابسکرایبکننده | بله |
| reference_id | Integer (FK→clinic│doc) | کلینیک یا دکتر مربوطه | بله |
| amount | Decimal | مبلغ اشتراک | بله |
| payment_method | String | روش پرداخت | بله |
| payment_time | Timestamp | زمان پرداخت | بله |
| start_date | Timestamp | تاریخ شروع اشتراک | بله |
| expiration_date | Timestamp | تاریخ انقضای اشتراک | بله |
| ref_id | String | شماره مرجع درگاه | بله |
| card_info | JSON | اطلاعات ماسکشده کارت | بله |
| representation | Integer (FK→rep) | نماینده (در صورت وجود) | اختیاری |
| frontend_address | String (URL) | آدرس بازگشت | بله |
| status | Enum | pending │ received │ refund │ canceled | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۱۱ پروفایل بیمار (Profile)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ----------------------- | ----------------- | -------------------------------------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | کاربر مرتبط | بله |
| national_code | String (10 رقم) | کد ملی | بله |
| national_code_approved | Boolean | تأیید کد ملی | بله |
| date_of_birth | Timestamp | تاریخ تولد | بله |
| gender | Enum | male │ female │ other | بله |
| blood_type | Enum | A+ │ A- │ B+ │ B- │ O+ │ O- │ AB+ │ AB- | بله |
| education | Enum | diploma │ postgraduate_diploma │ bachelor_s_degree │ master_s_degree │ doctorate | بله |
| fathers_name | String | نام پدر | اختیاری |
| family | String | وضعیت تأهل | اختیاری |
| job | String | شغل | اختیاری |
| address | Text | آدرس محل سکونت | اختیاری |
| home_phone | String | تلفن منزل | اختیاری |
| work_phone | String | تلفن محل کار | اختیاری |
| basic_insurance | Integer (FK→ins) | بیمه پایه | اختیاری |
| supplementary_insurance | Integer (FK→ins) | بیمه مکمل | اختیاری |
| insurance_id | String | شماره عضویت بیمه | اختیاری |
| other | JSON | متادیتای قابل توسعه | اختیاری |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۱۲ وبلاگ (Blog)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | --------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uuid | UUID | شناسه یکتا | بله |
| uid | Integer (FK→User) | نویسنده | بله |
| label | String | عنوان پست | بله |
| status | Boolean | منتشرشده / پیشنویس | بله |
| top | Boolean | پست برجسته / پینشده | بله |
| images | Array (حداکثر ۵) | حداکثر ۵ تصویر | بله |
| tag | Array (حداکثر ۵) | حداکثر ۵ تگ دستهبندی | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۲.۱۳ نظرات، لایک و امتیازدهی
### ۲.۱۳.۱ نظر (Comment)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | -------------------- | ------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uid | Integer (FK→User) | کاربر نظردهنده | بله |
| doctor_id | Integer (FK→doctor) | دکتر مورد نظر | بله |
| comment | Text | متن نظر | بله |
| parent | Integer (FK→comment) | نظر والد (برای پاسخهای تودرتو) | اختیاری |
| Approved | Boolean | وضعیت تأیید از سوی مدیر | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۱۳.۲ لایک (Like)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | -------------------- | ----------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uid | Integer (FK→User) | کاربر | بله |
| comment_id | Integer (FK→comment) | نظر هدف | بله |
| like | Boolean | true = لایک، false = دیسلایک | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
### ۲.۱۳.۳ امتیاز (Rate)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ---------------------- | ------------------- | ------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uid | Integer (FK→User) | کاربر امتیازدهنده | بله |
| doctor_id | Integer (FK→doctor) | دکتر امتیازگیرنده | بله |
| starts | Decimal | امتیاز ستارهای کلی (مثلاً ۴.۵) | بله |
| percent | Float | درصد امتیاز کلی | بله |
| doctor_behavior | Integer (۱-۵) | امتیاز برخورد دکتر | بله |
| accuracy_of_diagnosis | Integer (۱-۵) | امتیاز دقت تشخیص | بله |
| waiting_time_at_clinic | Integer (۱-۵) | امتیاز زمان انتظار | بله |
| doctor_expertise | Integer (۱-۵) | امتیاز تخصص دکتر | بله |
| clinic_cleanliness | Integer (۱-۵) | امتیاز نظافت کلینیک | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
# ۳. مشخصات API
تمام APIها باید بر اساس clini_pro.json مستند شوند و ورودی، خروجی و کدهای خطا به صورت کامل مشخص باشند.
## Task-02: احراز هویت (Authentication)
**⚠ اصلاح شده: فقط کاربران با نقش doctor، clinic یا doctor_s_secretary میتوانند با نام کاربری/رمز عبور لاگین کنند. مسیر /oauth/userinfo باید دقیقاً شبیه به بکاند دروپال طراحی شود.**
### POST /oauth/token — ورود به سیستم
| **Endpoint** | POST /oauth/token |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | POST |
| **ورودی** | Content-Type: application/x-www-form-urlencoded grant_type: password username: password: client_id: client_secret: |
| خروجی | HTTP 200 { access_token: string, token_type: "Bearer", expires_in: number, refresh_token: string, scope: string } |
| **خطاها** | 400 invalid_request — پارامتر اجباری ارسال نشده 401 invalid_client — اعتبارنامه نادرست 401 invalid_grant — نام کاربری یا رمز اشتباه 403 unauthorized_client — نقش کاربر مجاز نیست (فقط: doctor, clinic, doctor_s_secretary) 500 server_error |
### GET /oauth/userinfo — اطلاعات کاربر (سازگار با دروپال)
| **Endpoint** | GET /oauth/userinfo |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Header: Authorization: Bearer |
| خروجی | HTTP 200 { sub: string (uid), name: string (realname), preferred_username: string (mobile_number), email: string │ null, picture: string │ null, roles: string[], status: boolean, uid: number, uuid: string } نکته: ساختار پاسخ باید دقیقاً با /oauth/userinfo دروپال یکسان باشد. |
| **خطاها** | 401 Unauthorized — توکن موجود نیست یا نامعتبر است 403 Forbidden — توکن معتبر اما حساب غیرفعال است 500 server_error |
### POST /oauth/token — تجدید توکن (Refresh)
| **Endpoint** | POST /oauth/token (refresh) |
| ------------ | -------------------------------------------------------------------------------------------------------------- |
| Method | POST |
| **ورودی** | grant_type: refresh_token refresh_token: client_id: client_secret: |
| خروجی | HTTP 200 { access_token: string, token_type: "Bearer", expires_in: number, refresh_token: string } |
| **خطاها** | 400 invalid_request 401 invalid_grant — refresh token منقضی یا نامعتبر 500 server_error |
## Task-05: API دکتر
**⚠ اصلاح شده: آرایههای services و insurances باید در تمام پاسخها شامل id و label (نام) باشند.**
### GET /api/v1/doctors/{id}
| **Endpoint** | GET /api/v1/doctors/{id} |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Method | GET |
| **ورودی** | Path: id (integer) — شناسه دکتر Header: Authorization: Bearer (اختیاری برای داده عمومی) |
| خروجی | HTTP 200 { id, uuid, name, gender, degree, clinic_specialty: { id, label }, doctor_services: [{ id, label }, ...], ← الزامی state: { id, label }, city: { id, label }, representation: { id, label } │ null, active_doctor_appointment: boolean, doctor_rate, doctor_rate_percentage, images: [], info, activity_time } |
| **خطاها** | 404 Not Found — دکتر یافت نشد 403 Forbidden — دسترسی کافی نیست 500 server_error |
### GET /api/v1/doctors/{id}/insurances
| **Endpoint** | GET /api/v1/doctors/{id}/insurances |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Path: id (integer) — شناسه دکتر |
| خروجی | HTTP 200 { basic_insurance: [{ id, label, logo }, ...], supplementary_insurance: [{ id, label, logo }, ...] } نکته: هر آیتم باید id و label داشته باشد. |
| **خطاها** | 404 Not Found 500 server_error |
## Task-07: API نماینده (Agent)
**⚠ اصلاح شده: استان، شهر و شماره کارت بانکی باید در پاسخها وجود داشته باشند.**
### GET /api/v1/representations/{id}
| **Endpoint** | GET /api/v1/representations/{id} |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Path: id (integer) Header: Authorization: Bearer |
| خروجی | HTTP 200 { id, uuid, label, active, state: { id, label }, ← الزامی city: { id, label }, ← الزامی domain, address, bank_account: [ { card_number, bank_name, is_default: true }, { card_number, bank_name, is_default: false } ], ← الزامی (آرایه با یک دیفالت) commission_percent } |
| **خطاها** | 404 Not Found 403 Forbidden 500 server_error |
### POST /api/v1/representations/{id}/bank-accounts
| **Endpoint** | POST /api/v1/representations/{id}/bank-accounts |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | POST |
| **ورودی** | Header: Authorization: Bearer Body (JSON): { card_number: string (16 رقم), bank_name: string, is_default: boolean } نکته: اگر is_default=true باشد، دیفالت سایر کارتها لغو میشود. |
| خروجی | HTTP 201 Created { success: true, bank_account: { card_number, bank_name, is_default } } |
| **خطاها** | 400 Bad Request — فرمت شماره کارت نامعتبر 409 Conflict — کارت قبلاً ثبت شده 403 Forbidden 500 server_error |
## Task-08: API دستهبندیها
**⚠ اصلاح شده: استانها و شهرها درست تنظیم نشدهاند. تمام endpoint های دستهبندی باید داده کامل برگردانند.**
### GET /api/v1/categories/states — استانها
| **Endpoint** | GET /api/v1/categories/states |
| ------------ | -------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Query: ?status=1 (اختیاری) Header: Authorization: Bearer |
| خروجی | HTTP 200 { data: [ { id, uuid, label, status }, ... ], total: number } |
| **خطاها** | 401 Unauthorized 500 server_error |
### GET /api/v1/categories/cities — شهرها
| **Endpoint** | GET /api/v1/categories/cities |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Query: ?state_id=&status=1 (اختیاری) Header: Authorization: Bearer |
| خروجی | HTTP 200 { data: [ { id, uuid, label, status, parent: { id, label }, ← ارجاع به استان domain, representation }, ... ], total: number } |
| **خطاها** | 400 Bad Request — state_id نامعتبر 401 Unauthorized 500 server_error |
### سایر Endpoint های دستهبندی — الزامی
| **Endpoint** | **فیلدهای بازگشتی** |
| ----------------------------------------------- | ------------------------------- |
| GET /api/v1/categories/tags | id, uuid, label, status |
| GET /api/v1/categories/basic-insurances | id, uuid, label, logo, status |
| GET /api/v1/categories/supplementary-insurances | id, uuid, label, logo, status |
| GET /api/v1/categories/specialties | id, uuid, label, parent, status |
| GET /api/v1/categories/doctor-services | id, uuid, label, status |
## Task-09: API تنظیمات نوبت
### GET /api/v1/appointment-settings/slots — دریافت اسلاتهای خالی
| **Endpoint** | GET /api/v1/appointment-settings/slots |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Query: doctor_id: integer (الزامی) date: string YYYY-MM-DD (الزامی) Header: Authorization: Bearer |
| خروجی | HTTP 200 { date: string, doctor_id: integer, is_holiday: boolean, is_overridden: boolean, schedule_source: 'override' │ 'holiday_closed' │ 'weekly_schedule', available_slots: [ { slot_index, start_time, end_time, is_available }, ... ] } الگوریتم: Override > تعطیلی > برنامه هفتگی |
| **خطاها** | 400 Bad Request — پارامتر اجباری ارسال نشده 404 Not Found — دکتر یافت نشد 500 server_error |
### POST /api/v1/appointment-settings/overrides — ثبت Override توسط دکتر
| **Endpoint** | POST /api/v1/appointment-settings/overrides |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | POST |
| **ورودی** | Header: Authorization: Bearer Body (JSON): { doctor_id: integer, date: string YYYY-MM-DD, setting: { slots: [{ start_time, end_time, capacity }] }, active: boolean } |
| خروجی | HTTP 201 Created { id, uuid, doctor_id, date, setting, active, created } |
| **خطاها** | 400 Bad Request — تاریخ یا تنظیم نامعتبر 403 Forbidden — دکتر مجاز به تغییر Override دیگری نیست 409 Conflict — Override برای این تاریخ قبلاً وجود دارد 500 server_error |
### POST /api/v1/appointment-settings/holidays — ثبت تعطیلی (فقط ادمین)
| **Endpoint** | POST /api/v1/appointment-settings/holidays |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Method | POST |
| **ورودی** | Header: Authorization: Bearer Body (JSON): { label: string, date: string YYYY-MM-DD, active: boolean } |
| خروجی | HTTP 201 Created { id, uuid, label, date, active, created } |
| **خطاها** | 400 Bad Request — تاریخ نامعتبر 403 Forbidden — درخواستدهنده ادمین نیست 409 Conflict — تعطیلی برای این تاریخ قبلاً ثبت شده 500 server_error |
# ۴. سیستم حساب و صف پیامک
## ۴.۱ حساب پیامک (SMS Account)
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ------------ | ----------------- | ---------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| uid | Integer (FK→User) | کاربر مالک (دکتر یا کلینیک) | بله |
| owner_type | Enum | doctor │ clinic | بله |
| owner_id | Integer | FK به doctor.id یا clinic.id | بله |
| balance | Integer | تعداد پیامک باقیمانده | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۴.۲ صف پیامک (SMS Queue)
نرمافزار لوکال (Tauri) جابهای ارسال پیامک ایجاد میکند. بکاند آنها را در صف قرار میدهد و با هر ارسال، از موجودی کسر میکند.
| **نام فیلد** | **نوع داده** | **توضیحات** | **الزامی** |
| ---------------- | --------------------- | ----------------------------------------------------- | ---------- |
| id | Integer (PK) | کلید اصلی | بله |
| owner_id | Integer (FK→sms_acct) | حساب پیامک مالک | بله |
| recipient_mobile | String | شماره موبایل گیرنده | بله |
| message | Text | متن پیامک | بله |
| scheduled_at | Timestamp | زمان برنامهریزیشده ارسال (مثلاً یک روز قبل از نوبت) | بله |
| sent_at | Timestamp | زمان واقعی ارسال | اختیاری |
| status | Enum | queued │ sent │ failed │ cancelled | بله |
| created | Timestamp | زمان ایجاد | بله |
| changed | Timestamp | آخرین ویرایش | بله |
## ۴.۳ API پیامک
### POST /api/v1/sms/queue — افزودن به صف
| **Endpoint** | POST /api/v1/sms/queue |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| Method | POST |
| **ورودی** | Header: Authorization: Bearer Body (JSON): { recipient_mobile: string, message: string, scheduled_at: ISO8601 timestamp } |
| خروجی | HTTP 201 Created { id, status: 'queued', scheduled_at, remaining_balance: integer } |
| **خطاها** | 400 Bad Request — شماره موبایل یا پیام نامعتبر 402 Payment Required — موجودی پیامک کافی نیست 403 Forbidden 500 server_error |
### GET /api/v1/sms/balance — موجودی حساب پیامک
| **Endpoint** | GET /api/v1/sms/balance |
| ------------ | --------------------------------------------------------------------------------------- |
| Method | GET |
| **ورودی** | Header: Authorization: Bearer |
| خروجی | HTTP 200 { owner_id: integer, owner_type: 'doctor' │ 'clinic', balance: integer } |
| **خطاها** | 401 Unauthorized 404 Not Found — حساب پیامک وجود ندارد 500 server_error |
# ۵. فهرست مشکلات شناساییشده و اصلاحات لازم
| **تسک** | **مشکل** | **اصلاح مورد نیاز** | **وضعیت** |
| ------- | -------------------------------------- | --------------------------------------------------------------- | --------- |
| عمومی | جدول کاربران درست ایجاد نشده | بازسازی با تمام فیلدهای بخش ۲.۱ | 🔴 باز |
| عمومی | جدول نقشها درست ایجاد نشده | تعریف Enum نقشها و اتصال به کاربر | 🔴 باز |
| عمومی | ورودی/خروجی/خطاهای API تعریف نشده | تمام APIها باید I/O و کد خطا بر اساس clini_pro.json داشته باشند | 🔴 باز |
| Task-02 | لاگین فقط برای نقشهای مجاز | فقط doctor, clinic, doctor_s_secretary مجاز به لاگین هستند | 🔴 باز |
| Task-02 | oauth/userinfo با دروپال یکسان نیست | ساختار پاسخ باید دقیقاً با بکاند دروپال یکسان باشد | 🔴 باز |
| Task-05 | services/insurances فاقد id+name هستند | هر آیتم باید { id, label } داشته باشد | 🔴 باز |
| Task-07 | استان و شهر نماینده ندارد | فیلد state و city به موجودیت representation اضافه شود | 🔴 باز |
| Task-07 | اطلاعات کارت بانکی وجود ندارد | bank_account به صورت آرایه JSON با is_default اضافه شود | 🔴 باز |
| Task-08 | استان/شهر درست ست نشده | FK والد در city و endpoint استان باید داده کامل برگرداند | 🔴 باز |
| Task-08 | سایر دستهبندیها ناقص هستند | همه دستهبندیها باید فیلد کامل برگردانند | 🔴 باز |
| Task-09 | ثبت تعطیلی فقط توسط ادمین نیست | endpoint تعطیلات باید نقش admin بررسی کند | 🔴 باز |
| Task-09 | Override دکتر پیادهسازی نشده | موجودیت Date Override با دسترسی دکتر اضافه شود | 🔴 باز |
| Task-09 | اولویت الگوریتم اسلات اشتباه است | اولویت: Override > تعطیلی > برنامه هفتگی | 🔴 باز |
# ۶. پیوست
## ۶.۱ دیاگرام وضعیت نوبت
- ایجاد با پرداخت آنلاین ← waiting_for_payment ← reserved (پس از پرداخت)
- عدم پرداخت ← auto_cancel_unpaid
- لغو توسط بیمار ← cancelled_by_patient
- لغو توسط دکتر ← cancelled_by_doctor
- ورود بیمار ← checked_in ← waiting ← in_progress ← visited یا no_show
- تکمیل ← completed
- تعویق ← postponed
## ۶.۲ جریان کمیسیون
- بیمار از طریق دامنه نماینده نوبت رزرو میکند
- مبلغ کمیسیون (قابل تنظیم در ادمین) به کیف پول نماینده واریز میشود
- نکته مهم: کمیسیون از حق نوبتگیری است، نه از مبلغ کل نوبت
- در صورت سابسکرایب پلن توسط دکتر: کمیسیون به کیف پول نماینده مربوطه واریز میشود
## ۶.۳ بررسی محدودیت منشی
- هنگام فعالسازی منشی: تعداد منشیهای فعال آن دکتر بررسی شود
- پلن بیسیک: اگر ۱ منشی فعال وجود دارد، ثبت جدید رد شود
- پلن پیشرفته: اگر ۳ منشی فعال وجود دارد، ثبت جدید رد شود
- این بررسی باید کاملاً در سمت سرور انجام شود
## ۶.۴ محدوده سیستم (Scope)
کلینیک پرو صرفاً موارد زیر را هندل میکند:
- ثبتنام و احراز هویت کاربران
- نوبتدهی آنلاین
- مدیریت نماینده و کمیسیون
- مدیریت اشتراک
مدیریت جزئیات کلینیک، پرونده بیماران و سایر عملکردهای پیشرفته توسط نرمافزار لوکال Tauri هندل میشود و در اسکوپ این PRD نیست.
---
# بخش دوم — مستند کامل API
---
## فهرست مطالب
1. [احراز هویت (Authentication)](#1)
2. [کاربر (User)](#2)
3. [پروفایل بیمار (User Profile)](#3)
4. [دکتر (Doctor)](#4)
5. [آدرس دکتر (Doctor Address)](#5)
6. [کلینیک (Clinic)](#6)
7. [نماینده (Agent / Representation)](#7)
8. [دستهبندیها (Categories)](#8)
9. [بیمه دکتر (Doctor Insurance)](#9)
10. [تنظیمات نوبت — برنامه هفتگی](#10)
11. [تنظیمات نوبت — Date Override](#11)
12. [تنظیمات نوبت — تعطیلات](#12)
13. [نوبتدهی (Appointment)](#13)
14. [منشی (Secretary)](#14)
15. [پرداخت (Payment)](#15)
16. [وبلاگ (Blog)](#16)
---
## خطاهای عمومی
| کد HTTP | عنوان | توضیح |
| ------- | --------------------- | ---------------------------------- |
| `400` | Bad Request | پارامتر اجباری نیست یا فرمت نادرست |
| `401` | Unauthorized | توکن Bearer نامعتبر یا منقضی شده |
| `403` | Forbidden | دسترسی مجاز نیست |
| `404` | Not Found | منبع یافت نشد |
| `422` | Unprocessable Entity | اعتبارسنجی داده شکست خورد |
| `500` | Internal Server Error | خطای داخلی سرور |
---
## 1. احراز هویت (Authentication)
### 1. 🔵 `POST` refresh token
```
POST /oauth/token
```
**🔓 احراز هویت:** الزامی نیست
#### Request Body
| فیلد | نوع | الزامی | توضیح / مثال |
| --------------- | ------ | ------ | --------------- |
| `grant_type` | string | ✅ | `refresh_token` |
| `client_id` | string | ✅ | |
| `client_secret` | string | ✅ | |
| `refresh_token` | string | ✅ | |
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 2. 🟢 `GET` X-CSRF-Token
```
GET /session/token
```
**🔓 احراز هویت:** الزامی نیست
> این API برای دریافت توکن CSRF از سرور استفاده میشود. این توکن برای ارسال درخواستهای امن POST، PUT، DELETE و PATCH در سیستم نیاز است.
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 3. 🟢 `GET` user info 🆕
```
GET /oauth/userinfo
```
**🔐 احراز هویت:** `Authorization: Bearer {access_token}` — الزامی
> این API اطلاعات کاربر احراز هویتشده را با استفاده از توکن JWT برمیگرداند. برای استفاده از این endpoint باید کاربر از قبل احراز هویت شده و یک access token معتبر در اختیار داشته باشد.
#### پاسخها
**`200` ✅**
| فیلد | نوع | مثال / توضیح |
| ---------------- | --------- | ------------------------------------ |
| `email` | null | null |
| `email_verified` | boolean | true |
| `username` | string | 09120671710 |
| `id` | string | 22 |
| `uuid` | string | d200f5c5-d717-4526-b263-d3bb7d0228d6 |
| `created` | string | 1762262151 |
| `changed` | string | 1762262267 |
| `status` | string | 1 |
| `roles` | object | {0, 2} |
| `realName` | string | single doctor |
| `picture` | array (0) | [] |
| `clinic_pro` | object | {base_role, db_uuid, db_key...} |
مثال کامل Response (کلیک کنید)
```json
{
"email": null,
"email_verified": true,
"username": "09120671710",
"id": "22",
"uuid": "d200f5c5-d717-4526-b263-d3bb7d0228d6",
"created": "1762262151",
"changed": "1762262267",
"status": "1",
"roles": {
"0": "authenticated",
"2": "doctor"
},
"realName": "single doctor",
"picture": [],
"clinic_pro": {
"base_role": "doctor",
"db_uuid": "61be915b-595a-42e5-bca5-f80d22f4f14a",
"db_key": "22bea8c1dc64d9b0c744810722519efe7290276ecd82d9bc650482aa4539bf0d",
"my_doctors_uuid": {
"uuid": "61be915b-595a-42e5-bca5-f80d22f4f14a",
"id": "29",
"name": "single doctor"
}
}
}
```
---
## 2. کاربر (User)
### 4. 🔵 `POST` verify code
```
POST /api/v1/user/verify-code
```
**🔓 احراز هویت:** الزامی نیست
#### Request Body
| فیلد | نوع | الزامی | توضیح / مثال |
| --------------- | ------ | ------ | ------------ |
| `mobile` | string | ✅ | |
| `captcha_token` | string | ✅ | |
#### مثال Request
```json
{
"mobile": "09120671713",
"captcha_token": ""
}
```
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 5. 🔵 `POST` send code
```
POST /api/v1/user/send-code
```
**🔓 احراز هویت:** الزامی نیست
> ارسال کد تأیید موبایل Endpoint POST https://back-dev. توضیح این درخواست برای ارسال کد تأیید (OTP) به شماره موبایل کاربر استفاده میشود.
#### Request Body
| فیلد | نوع | الزامی | توضیح / مثال |
| --------------- | ------ | ------ | ------------ |
| `mobile` | string | ✅ | |
| `captcha_token` | string | ✅ | |
#### مثال Request
```json
{
"mobile": "09120671713",
"captcha_token": ""
}
```
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 6. 🔵 `POST` register
```
POST /api/v1/user/register
```
**🔓 احراز هویت:** الزامی نیست
#### هدرهای اضافی
| هدر | نوع | الزامی | توضیح |
| -------------- | ------ | ------ | ----- |
| `X-CSRF-Token` | string | ✅ | |
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 7. 🔴 `DELETE` delete user
```
DELETE /api/v1/user/5
```
**🔐 احراز هویت:** `Authorization: Bearer {access_token}` — الزامی
#### هدرهای اضافی
| هدر | نوع | الزامی | توضیح |
| -------------- | ------ | ------ | ----- |
| `X-CSRF-Token` | string | ✅ | |
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 8. 🟡 `PATCH` patch
```
PATCH /api/v1/user/2
```
**🔐 احراز هویت:** `Authorization: Bearer {access_token}` — الزامی
#### هدرهای اضافی
| هدر | نوع | الزامی | توضیح |
| -------------- | ------ | ------ | ----- |
| `X-CSRF-Token` | string | ✅ | |
#### Request Body
| فیلد | نوع | الزامی | توضیح / مثال |
| -------------- | ------ | ------ | ------------ |
| `field_name` | string | ✅ | |
| `field_family` | string | ✅ | |
| `mail` | string | ✅ | |
#### مثال Request
```json
{
"field_name": "سحر ",
"field_family": "صادقی",
"mail": "hamedhosseini0143@gmail.com"
}
```
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
### 9. 🟢 `GET` list secretary
```
GET /api/v1/secretaries/be1fc63e-0207-4fe4-a58b-5ac30953b742
```
**🔐 احراز هویت:** `Authorization: Bearer {access_token}` — الزامی
#### پارامترهای Query
| پارامتر | نوع | الزامی | توضیح |
| -------- | ------ | ------ | ---------------- |
| `active` | string | ✅ | — مثال: `active` |
#### هدرهای اضافی
| هدر | نوع | الزامی | توضیح |
| -------------- | ------ | ------ | ----- |
| `X-CSRF-Token` | string | ✅ | |
| `Content-Type` | string | ✅ | |
#### پاسخها
**`200` ✅**
> ⚠️ ساختار پاسخ مستند نشده — باید در Symfony تعریف و مستند شود.
---
## 3. پروفایل بیمار (User Profile)
### 10. 🔵 `POST` post
```
POST /api/v1/user-profile
```
**🔐 احراز هویت:** `Authorization: Bearer {access_token}` — الزامی
#### هدرهای اضافی
| هدر | نوع | الزامی | توضیح |
| -------------- | ------ | ------ | ----- |
| `X-CSRF-Token` | string | ✅ | |
#### Request Body
| فیلد | نوع | الزامی | توضیح / مثال |
| ------------------------- | ---------------- | ------ | ------------ |
| `name` | string | ✅ | |
| `description` | array\