24 KiB
ساخت تسکهای فاز ۲ — ClinicPro
زمینه
PRD فاز ۲ در docs/PRD/prd.md تعریف شده و شامل ۷ اپیک است. باید برای هر اپیک یک پوشه تسک در docs/tasks/ با فایلهای task.md، architecture.md، database.md و user_flow.md ایجاد شود — دقیقاً مطابق ساختار docs/tasks/task-09-appointment-settings/.
وضعیت فعلی
ساختار نمونه (task-09):
docs/tasks/task-09-appointment-settings/
task.md ← endpoints، نمونه request/response، پیشنیازها، زمان تخمینی
architecture.md ← ساختار فایلهای src/، نمونه entity با Doctrine annotations
database.md ← جداول، ستونها با نوع دقیق، ایندکسها، ساختار JSON ها
user_flow.md ← جریان کاربری با pseudocode و diagram ASCII
مسیر نهایی تسکهای جدید:
docs/phase2_taskes/task-10-staff/
docs/phase2_taskes/task-11-subscription/
docs/phase2_taskes/task-12-secretary-completion/
docs/phase2_taskes/task-13-clinic-services/
docs/phase2_taskes/task-14-sms-panel/
docs/phase2_taskes/task-15-patient-records/
docs/phase2_taskes/task-16-smart-dashboard/
API های موجود (نیازی به پیادهسازی ندارند):
/api/v1/secretary*— SecretaryController موجود است/api/v1/subscription-paymentو/api/v1/subscription-payment/callback/{gateway}— موجود است/api/v1/sms/send,/api/v1/sms/template*— موجود است/api/v1/wallet/*— WalletTransaction موجود است (برای SMS wallet الگو میگیریم)
Entities موجود مرتبط:
src/Secretary/Entity/DoctorSecretary.php— DEFAULT_PERMISSIONS ساختار permissionssrc/Settlement/Entity/WalletTransaction.php— الگوی wallet برای SmsWalletsrc/Payment/Entity/Payment.php—TYPE_SUBSCRIPTIONconst موجود استsrc/Sms/Entity/SmsLog.php,SmsTemplate.php— زیرساخت SMS موجود
قوانین کلی ساختار فایل
قوانین entity در architecture.md:
// همه entity های جدید از این الگو پیروی میکنند:
#[ORM\Entity]
#[ORM\Table(name: 'table_name')]
class EntityName
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 36, unique: true)]
private string $uuid;
// polymorphic pattern:
#[ORM\Column(type: 'string', length: 10)]
private string $entityType; // 'doctor' | 'clinic'
#[ORM\Column(type: 'integer')]
private int $entityId;
#[ORM\Column(type: 'integer')]
private int $createdAt;
#[ORM\Column(type: 'integer')]
private int $updatedAt;
}
قوانین controller:
// همه controller ها از BaseController ارث میبرند
class XxxController extends BaseController
{
// پاسخ موفق: $this->success($data)
// لیست paginated: $this->paginated($items, $total, $page, $limit)
// خطا: $this->error(ErrorCodes::ERR_XXX, 'پیام', Response::HTTP_XXX)
// خطای validation: $this->validationError($violations)
}
قوانین database.md:
- تاریخها همه
INT NOT NULL(Unix timestamp) هستند — هیچگاه DATETIME نه uuidهمیشهCHAR(36) UNIQUE NOT NULLentity_typeهمیشهVARCHAR(10)با مقادیر'doctor'یا'clinic'entity_idهمیشهINT NOT NULL(FK به doctors.id یا clinics.id بسته به entity_type)
وظایف
۱. ساخت docs/tasks/task-10-staff/
پیشنیاز اپیک ۴ و ۶ — باید اول پیادهسازی شود.
task.md:
- عنوان: «تسک ۱۰: مدیریت پرسنل (Staff)»
- پیشنیازها: تسک ۰۲ (Auth)، تسک ۰۵ (Doctor)، تسک ۰۶ (Clinic)
- زمان تخمینی: ۶ تا ۸ ساعت
- Endpoints:
| متد | مسیر | توضیح | نیاز به Auth |
|---|---|---|---|
| GET | /api/v1/staff |
لیست پرسنل context جاری | بله (Doctor/Clinic) |
| POST | /api/v1/staff |
ایجاد پرسنل جدید | بله |
| PATCH | /api/v1/staff/{uuid} |
ویرایش اطلاعات | بله (مالک) |
| PATCH | /api/v1/staff/{uuid}/toggle |
فعال/غیرفعال | بله (مالک) |
نمونه Request و Response واقعی با json کامل.
architecture.md:
src/Staff/
├── Controller/StaffController.php
├── Entity/ClinicStaff.php
├── Repository/ClinicStaffRepository.php
└── Service/StaffService.php
Entity ClinicStaff با تمام فیلدها با Doctrine annotations دقیق.
database.md:
جدول clinic_staff:
- id INT UNSIGNED AUTO_INCREMENT PK
- uuid CHAR(36) UNIQUE NOT NULL
- entity_type VARCHAR(10) NOT NULL (
'doctor'|'clinic') - entity_id INT NOT NULL
- full_name VARCHAR(200) NOT NULL
- phone VARCHAR(20) NULL
- job_title VARCHAR(100) NULL
- address TEXT NULL
- national_code CHAR(10) NULL
- active TINYINT(1) NOT NULL DEFAULT 1
- created_at INT NOT NULL
- updated_at INT NOT NULL
ایندکس: idx_clinic_staff_entity ON clinic_staff(entity_type, entity_id, active)
user_flow.md:
جریان ایجاد پرسنل + جریان غیرفعالسازی (چرا حذف ممنوع است: تاریخچه سرویسها حفظ میشود).
۲. ساخت docs/tasks/task-11-subscription/
پیشنیاز همه gate check ها — باید دوم پیادهسازی شود.
task.md:
- عنوان: «تسک ۱۱: پنل اشتراکی (Subscription Tiers)»
- پیشنیازها: تسک ۰۲، تسک ۱۵ (Payment موجود)
- زمان تخمینی: ۱۴ تا ۱۶ ساعت
- Endpoints (جدید — هیچکدام موجود نیستند به جز
/api/v1/subscription-paymentکه payment callback را handle میکند):
| متد | مسیر | Permission | توضیح |
|---|---|---|---|
| GET | /api/v1/subscription/plans |
public | لیست پنلها + دورهها + قیمتها |
| GET | /api/v1/subscription/my |
doctor/clinic | اشتراک فعال + used_trial flag |
| POST | /api/v1/subscription/trial |
doctor/clinic | فعالسازی تریال Basic (یکبار) |
| GET | /api/v1/admin/subscription/plans |
ROLE_ADMIN | لیست پنلها |
| POST | /api/v1/admin/subscription/plan |
ROLE_ADMIN | ایجاد پنل |
| PATCH | /api/v1/admin/subscription/plan/{uuid} |
ROLE_ADMIN | ویرایش پنل |
| POST | /api/v1/admin/subscription/period |
ROLE_ADMIN | افزودن دوره |
| PATCH | /api/v1/admin/subscription/period/{uuid} |
ROLE_ADMIN | ویرایش دوره |
| DELETE | /api/v1/admin/subscription/period/{uuid} |
ROLE_ADMIN | غیرفعالسازی |
| GET | /api/v1/admin/subscription/report |
ROLE_ADMIN | گزارش فروش |
نکته: /api/v1/subscription-payment قبلاً در PaymentController موجود است — callback آن هم موجود است. فقط باید بعد از callback موفق، ClinicSubscription ساخته شود (این وابستگی باید توضیح داده شود).
نمونه Response برای GET /api/v1/subscription/my:
{
"success": true,
"data": {
"plan": { "name": "basic", "level": 1, "features": {"patient_records": true, "services": true} },
"period": { "label": "۶ ماهه", "duration_months": 6 },
"is_trial": false,
"starts_at": 1718000000,
"expires_at": 1733360000,
"used_trial": true
}
}
architecture.md:
src/Subscription/
├── Controller/SubscriptionController.php
├── Entity/
│ ├── SubscriptionPlan.php
│ ├── SubscriptionPeriod.php
│ └── ClinicSubscription.php
├── Repository/
│ ├── SubscriptionPlanRepository.php
│ ├── SubscriptionPeriodRepository.php
│ └── ClinicSubscriptionRepository.php
└── Service/
└── SubscriptionService.php ← hasFeature() gate method
SubscriptionService::hasFeature(string $feature): bool:
public function hasFeature(string $feature): bool
{
// 1. entity_type + entity_id از authStore JWT claim
// 2. آخرین ClinicSubscription فعال: expires_at > time() OR expires_at IS NULL
// 3. plan->features[$feature] === true
// برگشتی false → caller باید $this->error(ErrorCodes::ERR_SUBSCRIPTION_REQUIRED, ..., 403) بزند
}
Entityها با Doctrine annotations دقیق (نوع json برای features در SubscriptionPlan).
database.md:
سه جدول کامل:
subscription_plans:
- id, uuid, name VARCHAR(30) ('free'|'basic'|'professional'), level TINYINT, max_secretaries TINYINT
- features JSON (e.g.
{"patient_records": true, "services": true, "sms_panel": false}) - active TINYINT(1), created_at INT, updated_at INT
subscription_periods:
- id, uuid, plan_id INT FK→subscription_plans.id
- label VARCHAR(50), duration_months TINYINT, price_rials INT
- is_trial TINYINT(1) DEFAULT 0, active TINYINT(1), sort_order TINYINT
- created_at INT, updated_at INT
clinic_subscriptions:
- id, uuid, entity_type VARCHAR(10), entity_id INT
- plan_id INT FK→subscription_plans.id, period_id INT FK→subscription_periods.id
- payment_id INT NULL FK→payments.id (NULL برای تریال)
- is_trial TINYINT(1), starts_at INT, expires_at INT NULL (NULL = Free بینهایت)
- created_at INT
ایندکسها:
INDEX idx_clinic_subscriptions_entity ON clinic_subscriptions(entity_type, entity_id, expires_at);
UNIQUE idx_subscription_trial_once ON clinic_subscriptions(entity_type, entity_id, is_trial) -- جلوگیری از تریال مکرر
Seed data اولیه (باید در migration یا fixture باشد):
INSERT INTO subscription_plans (uuid, name, level, max_secretaries, features, active) VALUES
(UUID(), 'free', 0, 1, '{"patient_records":false,"services":false,"sms_panel":false}', 1),
(UUID(), 'basic', 1, 2, '{"patient_records":true,"services":true,"sms_panel":false}', 1),
(UUID(), 'professional', 2, 5, '{"patient_records":true,"services":true,"sms_panel":true}', 1);
user_flow.md:
- جریان خرید اشتراک (انتخاب پنل + دوره → payment → callback → ClinicSubscription)
- جریان تریال (check used_trial → POST /trial → ClinicSubscription بدون payment_id)
- جریان تمدید (expires_at قبلی + duration_months × 30 × 86400)
- gate check flow: هر endpoint protected →
hasFeature()→ 403 اگر false
۳. ساخت docs/tasks/task-12-secretary-completion/
task.md:
- عنوان: «تسک ۱۲: تکمیل منشی — محدودیت پنل + UI Permissions»
- پیشنیازها: تسک ۱۴ (Secretary — موجود)، تسک ۱۱ (Subscription)
- زمان تخمینی: ۴ تا ۵ ساعت
- هیچ endpoint جدیدی نیست — فقط تغییر در کد موجود:
- Backend:
src/Secretary/Controller/SecretaryController.php::create()— اضافه کردن gate check - Frontend:
assets/admin/pages/SecretariesPage.tsx— Modal ویرایش permissions
- Backend:
نمونه کد Backend تغییر (قبل/بعد):
// قبل:
public function create(Request $request): JsonResponse
{
// validate و ذخیره مستقیم
// بعد — باید اضافه شود:
public function create(Request $request): JsonResponse
{
$limit = $this->subscriptionService->getSecretaryLimit(); // 1 یا 2 یا 5
$current = $this->secretaryRepo->countActive($doctorId);
if ($current >= $limit) {
return $this->error(ErrorCodes::ERR_SECRETARY_LIMIT_REACHED, 'سقف منشی پنل رسیده است', 403);
}
نمونه کد Frontend permissions checkbox:
// در SecretariesPage.tsx — Modal ویرایش
// DoctorSecretary::DEFAULT_PERMISSIONS ساختار را نشان میدهد:
// resources: { appointments: { view, create, cancel, update_status }, addresses: {...}, ... }
// باید یک checkbox matrix رندر شود
architecture.md:
فایلهایی که تغییر میکنند (نه فایل جدید):
src/Secretary/Controller/SecretaryController.php— injectSubscriptionServiceassets/admin/pages/SecretariesPage.tsx— Modal با checkbox matrix
database.md:
- هیچ migration لازم نیست
- توضیح ستون
permissionsدر جدولdoctor_secretaries(JSON)
user_flow.md:
- جریان تلاش برای افزودن منشی جدید وقتی سقف پنل رسیده
- جریان ویرایش permissions منشی موجود
۴. ساخت docs/tasks/task-13-clinic-services/
task.md:
- عنوان: «تسک ۱۳: سرویسهای کلینیک (Clinic Services)»
- پیشنیازها: تسک ۱۰ (Staff)، تسک ۱۱ (Subscription — gate check)
- زمان تخمینی: ۸ تا ۱۰ ساعت
- gate: همه write endpoints نیاز به
hasFeature('services')دارند (Basic+ فقط) - Endpoints:
| متد | مسیر | توضیح |
|---|---|---|
| GET | /api/v1/service-sections |
لیست بخشها |
| POST | /api/v1/service-section |
ایجاد بخش (Basic+) |
| PATCH | /api/v1/service-section/{uuid} |
ویرایش |
| DELETE | /api/v1/service-section/{uuid} |
حذف |
| GET | /api/v1/service-items/{sectionUuid} |
لیست زیربخشهای یک بخش |
| POST | /api/v1/service-item |
ایجاد زیربخش (Basic+) |
| PATCH | /api/v1/service-item/{uuid} |
ویرایش |
| DELETE | /api/v1/service-item/{uuid} |
حذف |
architecture.md:
src/ClinicService/
├── Controller/ClinicServiceController.php
├── Entity/
│ ├── ServiceSection.php
│ └── ServiceItem.php
└── Repository/
├── ServiceSectionRepository.php
└── ServiceItemRepository.php
database.md:
service_sections:
- id, uuid, entity_type VARCHAR(10), entity_id INT, name VARCHAR(200), active TINYINT(1) DEFAULT 1
- created_at INT, updated_at INT
- INDEX:
idx_service_sections_entity ON service_sections(entity_type, entity_id)
service_items:
- id, uuid, section_id INT FK→service_sections.id ON DELETE CASCADE
- staff_id INT NULL FK→clinic_staff.id ON DELETE SET NULL
- name VARCHAR(200), price_rials INT NOT NULL DEFAULT 0, active TINYINT(1) DEFAULT 1
- created_at INT, updated_at INT
user_flow.md:
- جریان ایجاد ساختار دو سطحی (بخش → زیربخش)
- جریان انتخاب پرسنل انجامدهنده
- gate check — کاربر Free تلاش میکند سرویس بسازد → 403
۵. ساخت docs/tasks/task-14-sms-panel/
task.md:
- عنوان: «تسک ۱۴: پنل پیامکی — کیف پول + تنظیمات»
- پیشنیازها: تسک ۱۷ (SMS infrastructure موجود)، تسک ۱۵ (Payment موجود)
- زمان تخمینی: ۱۰ تا ۱۲ ساعت
- نکته:
src/Sms/وsrc/Settlement/موجودند — کد جدید درsrc/Sms/اضافه میشود - Endpoints جدید:
| متد | مسیر | Permission | توضیح |
|---|---|---|---|
| GET | /api/v1/sms/wallet/balance |
doctor/clinic | موجودی |
| POST | /api/v1/sms/wallet/charge |
doctor/clinic | شارژ — { gateway, amount_rials } |
| GET | /api/v1/sms/wallet/logs |
doctor/clinic | تاریخچه کسر/شارژ |
| GET | /api/v1/sms/settings |
doctor/clinic | تنظیمات |
| PATCH | /api/v1/sms/settings |
doctor/clinic | ذخیره تنظیمات |
| GET | /api/v1/admin/sms/wallet-report |
ROLE_ADMIN | گزارش مصرف |
architecture.md:
Entity های جدید در src/Sms/Entity/:
// SmsWallet.php — الگو از WalletTransaction.php در src/Settlement/Entity/
// SmsSettings.php — key-value per entity
Controller جدید: src/Sms/Controller/SmsWalletController.php
شارژ کیف پول: redirect به gateway موجود با Payment.type = 'sms_wallet' (const جدید در Payment entity)
database.md:
sms_wallets:
- id, entity_type VARCHAR(10), entity_id INT (UNIQUE PAIR)
- balance_rials INT NOT NULL DEFAULT 0, created_at INT, updated_at INT
- UNIQUE INDEX:
idx_sms_wallets_entity ON sms_wallets(entity_type, entity_id)
sms_wallet_transactions:
- id, uuid, sms_wallet_id INT FK→sms_wallets.id
- type VARCHAR(10) ('credit'|'debit'), amount_rials INT, description VARCHAR(255) NULL
- payment_id INT NULL FK→payments.id, created_at INT
sms_settings:
- id, entity_type VARCHAR(10), entity_id INT (UNIQUE PAIR)
- reminder_enabled TINYINT(1) DEFAULT 0, reminder_hours_before TINYINT DEFAULT 2
- post_visit_enabled TINYINT(1) DEFAULT 0, post_visit_text TEXT NULL, updated_at INT
- UNIQUE INDEX:
idx_sms_settings_entity ON sms_settings(entity_type, entity_id)
SiteConfig key جدید: sms_price_rials (ادمین مقدار میدهد)
user_flow.md:
- جریان شارژ کیف پول (مثل payment اما
type='sms_wallet') - جریان کسر خودکار هنگام ارسال پیامک (hook در SmsService)
- جریان تنظیم یادآوری خودکار
۶. ساخت docs/tasks/task-15-patient-records/
task.md:
- عنوان: «تسک ۱۵: پرونده بیمار (Patient Records)»
- پیشنیازها: تسک ۱۰ (Staff)، تسک ۱۱ (Subscription)، تسک ۱۳ (Services)
- زمان تخمینی: ۱۶ تا ۲۰ ساعت
- gate: همه endpoints نیاز به
hasFeature('patient_records')(Basic+ فقط) - Endpoints:
| متد | مسیر | توضیح |
|---|---|---|
| GET | /api/v1/patients |
لیست بیماران — query: ?search= |
| POST | /api/v1/patient |
ایجاد پرونده دستی |
| GET | /api/v1/patient/{uuid} |
جزئیات پرونده + خلاصه |
| GET | /api/v1/patient/{uuid}/sessions |
لیست مراجعات |
| POST | /api/v1/patient/{uuid}/session |
ثبت مراجعه جدید |
| PATCH | /api/v1/session/{uuid} |
ویرایش مراجعه |
نمونه Request ثبت سشن:
{
"appointment_uuid": "optional-uuid",
"insurance_base_uuid": "category-uuid",
"insurance_supplementary_uuid": null,
"visit_price_rials": 500000,
"base_insurance_discount_percent": 30,
"supplementary_discount_percent": 0,
"payment_method": "cash",
"notes": "...",
"services": [
{ "service_item_uuid": "...", "staff_uuid": "..." }
]
}
نمونه Response (final_price محاسبهشده):
{
"success": true,
"data": {
"uuid": "...",
"visit_price_rials": 500000,
"base_insurance_discount_percent": 30,
"supplementary_discount_percent": 0,
"services_total_rials": 150000,
"final_price_rials": 500000,
"payment_method": "cash"
}
}
فرمول محاسبه:
after_base = visit_price × (1 - base_discount/100)
after_supp = after_base × (1 - supp_discount/100)
final = round(after_supp) + sum(service_item.price_rials)
architecture.md:
src/Patient/
├── Controller/PatientController.php
├── Entity/
│ ├── PatientRecord.php
│ ├── PatientSession.php
│ └── SessionService.php
├── Repository/
│ ├── PatientRecordRepository.php
│ └── PatientSessionRepository.php
└── Service/
└── PatientService.php ← calculateFinalPrice(), autoCreateOnAppointmentConfirm()
نکته در architecture.md: autoCreateOnAppointmentConfirm() باید از AppointmentController::updateStatus() صدا شود — وقتی status به 'confirmed' تغییر میکند، PatientRecord چک/ایجاد میشود.
database.md:
patient_records:
- id, uuid, entity_type VARCHAR(10), entity_id INT
- user_id INT FK→users.id ON DELETE RESTRICT
- created_by_type VARCHAR(15) ('doctor'|'secretary'|'system'), created_by_id INT
- created_at INT
- UNIQUE:
idx_patient_record_unique ON patient_records(entity_type, entity_id, user_id)
patient_sessions:
- id, uuid, record_id INT FK→patient_records.id ON DELETE CASCADE
- appointment_id INT NULL FK→appointments.id ON DELETE SET NULL
- insurance_base_id INT NULL FK→categories.id, insurance_supplementary_id INT NULL FK→categories.id
- visit_price_rials INT NOT NULL DEFAULT 0
- base_insurance_discount_percent DECIMAL(5,2) DEFAULT 0
- supplementary_discount_percent DECIMAL(5,2) DEFAULT 0
- services_total_rials INT NOT NULL DEFAULT 0
- final_price_rials INT NOT NULL
- payment_method VARCHAR(15) ('cash'|'card'|'insurance'|'pending')
- notes TEXT NULL, created_at INT, updated_at INT
session_services:
- id, uuid, session_id INT FK→patient_sessions.id ON DELETE CASCADE
- service_item_id INT FK→service_items.id ON DELETE RESTRICT
- staff_id INT NULL FK→clinic_staff.id ON DELETE SET NULL
- price_rials INT NOT NULL ← کپی از service_item.price_rials در زمان ثبت
- created_at INT
ایندکسها:
INDEX idx_patient_records_entity ON patient_records(entity_type, entity_id);
INDEX idx_patient_sessions_record ON patient_sessions(record_id, created_at);
user_flow.md:
- جریان خودکار: تأیید نوبت → چک PatientRecord → ایجاد اگر نبود → ایجاد PatientSession
- جریان دستی: منشی/دکتر → جستجو بیمار → ایجاد پرونده → ثبت مراجعه + سرویسها
- محاسبه final_price با step by step مثال عددی
- جریان جستجو بیمار (search در patients API)
۷. ساخت docs/tasks/task-16-smart-dashboard/
task.md:
- عنوان: «تسک ۱۶: داشبورد هوشمند — چارت + فیلتر زمانی»
- پیشنیازها: همه تسکهای قبل — نیاز به داده واقعی دارد
- زمان تخمینی: ۸ تا ۱۰ ساعت
- هیچ endpoint جدیدی نیست — فقط پارامتر
fromوtoبه endpoint های موجود اضافه میشود:GET /api/v1/admin/dashboard/charts?from=UNIX&to=UNIXGET /api/v1/dashboard/clinic?from=UNIX&to=UNIXGET /api/v1/dashboard/doctor?from=UNIX&to=UNIX
فیلدهای جدید در response داشبورد کلینیک/دکتر:
{
"sms_wallet_balance": 150000,
"unique_patients_count": 45,
"revenue_current_month": 12500000
}
architecture.md:
فایلهایی که تغییر میکنند:
src/Dashboard/Controller/DashboardController.php— اضافه کردنfrom/toبه queryassets/admin/pages/DashboardPage.tsx— date range selector + نمودار (Recharts)
نکته: Recharts پیشنهادی است (سبک، tree-shakeable). نصب با yarn add recharts.
database.md:
- هیچ migration لازم نیست
- query های DQL که باید به
from/toمحدود شوند
user_flow.md:
- کاربر date range انتخاب میکند → charts refresh میشوند
- preset ها: «این هفته» / «این ماه» / «۳ ماه» / «سفارشی»
- تبدیل تاریخ شمسی به Unix timestamp برای ارسال به API
نکات مهم
- ترتیب پیادهسازی اجباری است: task-10 → task-11 → task-12 → task-13 → task-14 → task-15 → task-16
- حذف سخت ممنوع در ClinicStaff — فقط
active=false - UNIQUE constraint در تریال: یک entity نمیتواند دو بار از تریال استفاده کند — index روی
(entity_type, entity_id, is_trial)درclinic_subscriptions - price_rials در session_services کپی میشود — تغییر قیمت سرویس در آینده تأثیری روی سشنهای قبلی ندارد
- patient_records UNIQUE per entity+user — یک بیمار یک پرونده در هر کلینیک/مطب دارد (مراجعات چندگانه = سشنهای جداگانه در همان پرونده)
- فایل doc برای هر اپیک بعد از پیادهسازی باید ایجاد شود (
docs/api/staff.md،docs/api/subscription.md،docs/api/clinic-services.md،docs/api/patient.md)