Files
clinicpro/.claude/prompt/create-phase2-tasks.md
T

24 KiB
Raw Blame History

ساخت تسک‌های فاز ۲ — 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 ساختار permissions
  • src/Settlement/Entity/WalletTransaction.php — الگوی wallet برای SmsWallet
  • src/Payment/Entity/Payment.phpTYPE_SUBSCRIPTION const موجود است
  • 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 NULL
  • entity_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 تغییر (قبل/بعد):

// قبل:
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 — inject SubscriptionService
  • assets/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=UNIX
    • GET /api/v1/dashboard/clinic?from=UNIX&to=UNIX
    • GET /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 به query
  • assets/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)