Files
clinicpro/docs/new_feture/dental-module/README.md
T
hamed 2f030edef1 Add dental module phase 4 and phase 5 documentation, including treatment estimates, clinical operations, and preset content
- Introduced phase 4 documentation detailing treatment estimates, data models, state machines, API endpoints, and new dashboard metrics.
- Added phase 5 documentation covering consumables, lab operations, periodontal charts, sterilization cycles, clinical images, and a checklist for professional review.
- Created a preset content document outlining default dental service packages and protocols for clinics.
2026-08-20 16:21:08 +03:30

17 KiB
Raw Blame History

ماژول دندانپزشکی ClinicPro

دامنه: clinicpro — بک‌اند Symfony و پنل ادمین React وضعیت: سند طراحی. کد نوشته نشده. تاریخ: 2026-08 خارج از دامنه: بیمه. فقط نقطهٔ اتصال رزرو می‌شود.

این سند حاصل یک جلسهٔ تصمیم‌گیری روی کد واقعی ریپو است. هر بند «چه» را می‌گوید و «چرا» را کنارش. تصمیم‌ها در بخش ۳ فهرست‌اند و بقیهٔ سند نتیجهٔ آن‌هاست.

منبع اولیه‌اش سند clinicpro-dental-module-technical-spec.md در ریشهٔ workspace بود. آن سند بدون دسترسی به کد نوشته شده بود و بخش بزرگی از چیزی که پیشنهاد داده، از قبل ساخته شده است. بخش ۲ تفاوت‌ها را نشان می‌دهد.


۱. مسئله

خواسته یک جمله است. وقتی یک کلینیک حوزهٔ فعالیت «دندانپزشکی» را انتخاب می‌کند، باید دسته‌بندی‌ها و تنظیمات دندانپزشکی برایش ساخته شود و داشبورد مخصوص خودش را ببیند.

امروز انتخاب حوزهٔ فعالیت فقط یک کلید خارجی روی جدول کلینیک می‌نویسد. هیچ دسته‌ای، هیچ خدمتی، هیچ تنظیمی ساخته نمی‌شود. یعنی کلینیک بعد از انتخاب حوزه، دقیقاً همان‌قدر خالی است که قبلش بود.

سه تکهٔ خواسته:

۱. با انتخاب دندانپزشکی، کاتالوگ خدمات دندانپزشکی ساخته شود. ۲. دندانپزشک بتواند وضعیت دندان‌های بیمار را ثبت و ببیند. ۳. مدیر و پزشک و پذیرش، شاخص‌های دندانپزشکی را در داشبورد ببینند.


۲. آنچه امروز واقعاً هست

این بخش از روی کد نوشته شده، نه از روی مستندات.

۲.۱ حوزهٔ فعالیت — هست، ولی فقط برچسب است

چیز مسیر
موجودیت src/PracticeDomain/Entity/PracticeDomain.php
کنترلر src/PracticeDomain/Controller/PracticeDomainController.php
مستندات docs/api/practice-domain.md
اتصال به کلینیک src/Clinic/Entity/Clinic.php ستون practice_domain_id
صفحهٔ پنل assets/admin/pages/PracticeDomainSettingsPage.tsx

جدول سراسری است و در GlobalTables::ENTITIES ثبت شده. انتخاب حوزه از PATCH روی کلینیک با کلید practice_domain_uuid انجام می‌شود.

نکتهٔ مهم: Doctor این فیلد را ندارد. ولی مالکیت داده در کل پروژه دو حالته است، entity_type برابر doctor یا clinic. یعنی مطب تک‌پزشک امروز اصلاً نمی‌تواند حوزهٔ فعالیت انتخاب کند. این یک نقص عمومی است و فقط به دندانپزشکی مربوط نیست؛ کلینیک زیبایی تک‌پزشکه هم همین مشکل را دارد.

۲.۲ رفتار مخصوص هر حوزه — الگویش ساخته شده

چیز مسیر
اینترفیس src/Treatment/Workflow/TreatmentWorkflow.php
رجیستری src/Treatment/Workflow/TreatmentWorkflowRegistry.php
پیش‌فرض src/Treatment/Workflow/DefaultTreatmentWorkflow.php
نمونهٔ حوزه‌ای src/Treatment/Workflow/LaserTreatmentWorkflow.php
تصمیم ثبت‌شده docs/adr/0005-treatment-workflows-are-tagged-services.md

سرویس‌ها با تگ app.treatment_workflow ثبت می‌شوند و رجیستری بر اساس کد حوزه انتخاب می‌کند. افزودن دندانپزشکی یعنی یک کلاس تازه، نه دست‌بردن در مسیر رزرو.

۲.۳ کاتالوگ خدمات — کامل است

موجودیت نقش
ServiceSection بخش سازمانی کلینیک
CatalogCategory تاکسونومی درختی خدمات تا عمق ۴
ServiceItem خدمت با قیمت، مدت، تعداد جلسه، دستهٔ کاتالوگ
ItemGroup و ItemGroupMember گروه‌بندی آیتم
ServiceItemRelation رابطهٔ بین خدمات
ServiceBranchOverride بازنویسی قیمت در شعبه

مسیرها در src/ClinicService/. اندپوینت‌های موجود در docs/api/clinic-services.md. صفحات پنل: ClinicServicesPage.tsx و CatalogCategoriesPage.tsx.

۲.۴ یونیت و صندلی — لازم نیست ساخته شود

سند اولیه پیشنهاد جدول chairs و ستون chairId روی نوبت داده بود. هر دو از قبل هستند و بهترند:

چیز مسیر
نوع منبع با CODE_ROOM src/Resource/Entity/ResourceType.php
خود منبع src/Resource/Entity/ClinicResource.php
تقویم و استثنا src/Resource/Entity/ResourceCalendar.php و ResourceException.php
اتصال به نوبت src/Appointment/Entity/Appointment.php ستون resource_id
اشغال واقعی resource_occupancy
تصمیم ثبت‌شده docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md

منبع، ظرفیت و زمان آماده‌سازی و زمان تمیزکاری هم دارد. یعنی «۱۵ دقیقه بین دو بیمار برای ضدعفونی یونیت» بدون کد جدید قابل تنظیم است.

۲.۵ دوره درمان و جلسه — هست، ولی معنایش با دندانپزشکی یکی نیست

موجودیت معنی امروز
TreatmentProtocol قالب دوره‌ای یک خدمت، تعریف‌شده توسط مدیر
TreatmentCase یک بیمار، یک خدمت، از اولین رزرو تا پایان دوره
TreatmentSession جلسهٔ شماره‌دار همان دوره، بدون هیچ ستون پولی
TreatmentCaseArea ناحیهٔ بدن، اسنپ‌شات از CatalogCategory
SessionAreaRecord آنچه اپراتور روی هر ناحیه انجام داد
PatientSession سابقهٔ مالی یک ویزیت انجام‌شده
SessionService ردیف خدمت همان ویزیت با قیمت

واژگان در CONTEXT.md تعریف شده و صریحاً «Treatment Plan» را ممنوع کرده، چون بین قالب و دوره ابهام می‌ساخت.

فرق بنیادی: TreatmentCase یک خدمت دارد. طرح درمان دندانپزشکی ده‌ها خدمت روی دندان‌های مختلف دارد که بیمار بخشی را می‌پذیرد. این دو یکی نیستند و نباید یکی شوند.

۲.۶ داشبورد — چهار اندپوینت نقشی

src/Dashboard/Controller/DashboardController.php با ۸۰۳ خط و ۱۵ وابستگی، چهار مسیر دارد:

GET /api/v1/dashboard/clinic
GET /api/v1/dashboard/doctor
GET /api/v1/dashboard/secretary
GET /api/v1/dashboard/staff

هیچ‌کدام مفهوم حوزهٔ فعالیت را نمی‌شناسند.

۲.۷ آنچه واقعاً غایب است

فقط چهار چیز:

۱. حوزهٔ فعالیت روی مطب پزشک. ۲. ساخته‌شدن خودکار دادهٔ پیش‌فرض هنگام انتخاب حوزه. ۳. دندان به‌عنوان یک مفهوم — چارت، سطح، هدف‌گیری خدمت روی دندان. ۴. برآورد چندخدمتی و نرخ پذیرش آن.

هر چیز دیگری که سند اولیه پیشنهاد داده بود، از قبل هست.


۳. تصمیم‌ها

# تصمیم چرا
۱ ماژول داده‌محور است، نه یک دامنهٔ موازی موتور درمان و منبع و کاتالوگ از قبل هست. دامنهٔ موازی یعنی دو منبع حقیقت برای جلسه و اتاق.
۲ seed خودکار وقتی کاتالوگ خالی است، وگرنه دکمهٔ صریح با پیش‌نمایش کلینیک خالی حالت اصلی است. کلینیک پرداده نباید بی‌اجازه ادغام شود، چون بعداً تشخیص «این ردیف را من ساختم یا سیستم» ممکن نیست.
۳ قالب پیش‌فرض‌ها در کد است، در فایل نسخه‌دار محتوای محصول است نه دادهٔ کلینیک. باید در git تاریخچه و review و تست داشته باشد. تغییرش نادر است.
۴ دندان مفهوم مستقل است با شمارهٔ FDI از نوع smallint FDI واقعیت جهانی است نه تاکسونومی هر کلینیک. دندان به‌عنوان دستهٔ کاتالوگ یعنی ۳۲ ردیف تکراری در هر کلینیک، و «سطح دندان» و «وضعیت ماندگار» جایی برای نشستن ندارند.
۵ فاز ۱ بدون برآورد چندخدمتی جلو می‌رود زودتر به خروجی قابل استفاده می‌رسیم. هزینه‌اش این است که نرخ پذیرش تا فاز ۴ وجود ندارد و این باید در سند صریح بماند.
۶ داشبورد از یک registry متریک بر اساس حوزه سرو می‌شود همان الگوی TreatmentWorkflow که پروژه از قبل دارد. شرط‌گذاری داخل کنترلر ۸۰۳ خطی، چهار مسیر کد را دوبرابر می‌کند.
۷ حوزهٔ فعالیت به سطح محیط منتقل می‌شود، هم کلینیک هم مطب پزشک مطب تک‌پزشک بخش بزرگ بازار است. این نقص امروز حوزهٔ زیبایی را هم خراب می‌کند، پس اصلاحش عمومی است نه دندانی.
۸ شاخص‌ها در فاز ۱ زنده محاسبه می‌شوند هیچ اندازه‌گیری‌ای نشان نداده کند است. جدول تجمیع یعنی job شبانه، مسیر backfill، و منبع حقیقت دومی که می‌تواند واگرا شود.
۹ چارت هم از خدمت ویزیت پر می‌شود هم دستی ویرایش می‌شود چارت باید وضعیت‌هایی را نشان دهد که هرگز در این کلینیک فاکتور نشده‌اند، مثل دندان کشیده‌شدهٔ سال‌ها قبل. پس مشتق کامل ممکن نیست. ثبت فقط دستی هم یعنی ثبت دوباره و واگرایی از صورتحساب.
۱۰ ویژگی‌های دندانی خدمت در جدول توسعهٔ یک‌به‌یک می‌نشیند ServiceItem مشترک همهٔ حوزه‌هاست. ستون دندانی روی آن یعنی هر حوزهٔ بعدی هم ستون خودش را اضافه می‌کند.
۱۱ بستهٔ seed شامل دسته‌ها، خدمات با قیمت صفر، نوع منبع یونیت و پروتکل‌هاست دسته بدون خدمت کلینیک را دست‌خالی می‌گذارد. نمونهٔ یونیت ساختن، دادهٔ ساختگی در محیط واقعی جا می‌گذارد. تعداد یونیت را فقط خود مدیر می‌داند.
۱۲ نصب seed در یک جدول نگاشت در دامنهٔ Dental ثبت می‌شود؛ تغییر حوزه چیزی را حذف نمی‌کند با تصمیم ۱۰ قرار شد جدول‌های مشترک آلوده نشوند. خدمتی که یک بار در ویزیت استفاده شده اصلاً حذف‌شدنی نیست، کلید خارجی RESTRICT است.
۱۳ چارت یک تب تازه در پروندهٔ بیمار است؛ شاخص‌های دندانی بخشی از همان داشبورد فعلی دندانپزشک همیشه داخل پروندهٔ بیمار کار می‌کند. منوی جدا یعنی خروج مکرر از کانتکست بیمار.
۱۴ فهرست خدمات پیش‌نویس است و قبل از merge باید دندانپزشک تأییدش کند فهرست غلط بدتر از نبودن فهرست است، چون پاک‌کردنش از ده‌ها کلینیک دیگر ممکن نیست.

۴. واژگان تازه

این‌ها به CONTEXT.md اضافه شده‌اند. اینجا فقط خلاصه است.

Tooth Chart — نمای وضعیت جاری همهٔ دندان‌های یک بیمار در یک محیط. اسنپ‌شات است نه تاریخچه. پرهیز از: dental chart record, odontogram record.

Tooth Site — یک دندان مشخص با شمارهٔ FDI، به‌همراه سطوح درگیر. هدف یک خدمت دندانی. پرهیز از: Treatment Area, tooth record.

Dental Preset — بستهٔ دادهٔ پیش‌فرض حوزهٔ دندانپزشکی که با انتخاب حوزه در محیط نصب می‌شود. پرهیز از: seed, fixture, template.

Preset Install — رکورد نصب یک کلید قالب روی یک ردیف واقعی در یک محیط. مبنای idempotency. پرهیز از: migration, sync record.


۵. تصمیم‌های ثبت‌شده

ADR موضوع
docs/adr/0007-practice-domain-is-tenant-level.md حوزهٔ فعالیت مال محیط است نه فقط کلینیک
docs/adr/0008-teeth-are-not-treatment-areas.md دندان دستهٔ کاتالوگ نیست
docs/adr/0009-dental-service-attributes-live-in-an-extension-table.md ویژگی دندانی خدمت در جدول جدا
docs/adr/0010-domain-metrics-come-from-tagged-providers.md شاخص حوزه‌ای از provider تگ‌خورده

۶. فازها

فاز محتوا سند
۱ حوزه در سطح محیط، نصب پیش‌فرض‌ها، پروفایل دندانی خدمت phase-1-preset.md
۲ چارت دندان، هدف‌گیری دندان روی خدمت ویزیت، پروجکتور phase-2-tooth-chart.md
۳ registry متریک و شاخص‌های دندانپزشکی روی داشبورد phase-3-dashboard.md
۴ برآورد درمان و نرخ پذیرش phase-4-treatment-estimate.md
۵ پریو، لابراتوار، استریلیزاسیون، مواد مصرفی phase-5-clinical-ops.md

محتوای پیشنهادی بستهٔ پیش‌فرض در preset-content.md.

هر فاز بدون تست موفق و خطا و مرزی، و بدون به‌روزرسانی docs/api/، تمام‌شده نیست.


۷. قواعد مشترک همهٔ فازها

از CLAUDE.md پروژه، اینجا فقط یادآوری:

  • شناسه عددی به‌همراه uuid نسخهٔ ۴. uuid در پاسخ API، id هرگز.
  • تایم‌استمپ از نوع integer یونیکس.
  • نام جدول جمع و snake_case.
  • پاسخ از BaseController، خطا با AppException و ErrorCodes.
  • هر entity تازه باید جفت entity_type و entity_id داشته باشد، وگرنه TenantSchemaCoverageTest قرمز می‌شود.
  • کوئری‌های لیست با getArrayResult().
  • در پنل: SearchableSelect به‌جای select بومی، Switch به‌جای checkbox، رنگ فقط از var(--...).
  • تاریخ در دیتابیس میلادی ذخیره، در نمایش جلالی.

۸. مرزهای رزروشده

بیمه: دامنهٔ Insurance از قبل کامل است و شامل TenantServiceCoverage و TenantInsuranceCategoryCoverage و EntityInsurancePricing می‌شود. هیچ منطق بیمه‌ای در این ماژول نوشته نمی‌شود. تنها اثرش این است که ردیف برآورد در فاز ۴ باید ستون payer_type داشته باشد تا بعداً سند بیمه رویش بنشیند.

اپ Tauri: در فاز ۱ تا ۳ هیچ تغییری نمی‌گیرد. اگر بعداً چارت آفلاین لازم شد، tooth_chart و وضعیت دندان کاندیدهای خوبی هستند چون تک‌نویسنده و کم‌تعارض‌اند. برآورد درمان چون مالی است نباید last-write-wins بگیرد. این موضوع به سند sync ارجاع می‌شود، نه اینجا.

سایت عمومی nobat724: خدمات دندانپزشکی مثل هر خدمت دیگری در سایت دیده می‌شوند. هیچ تغییر اختصاصی لازم نیست مگر اینکه بخواهیم انتخاب دندان در رزرو آنلاین باشد، که خارج از این سند است.