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.
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
# ماژول دندانپزشکی 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-1-preset.md) |
|
||||
| ۲ | چارت دندان، هدفگیری دندان روی خدمت ویزیت، پروجکتور | [phase-2-tooth-chart.md](phase-2-tooth-chart.md) |
|
||||
| ۳ | registry متریک و شاخصهای دندانپزشکی روی داشبورد | [phase-3-dashboard.md](phase-3-dashboard.md) |
|
||||
| ۴ | برآورد درمان و نرخ پذیرش | [phase-4-treatment-estimate.md](phase-4-treatment-estimate.md) |
|
||||
| ۵ | پریو، لابراتوار، استریلیزاسیون، مواد مصرفی | [phase-5-clinical-ops.md](phase-5-clinical-ops.md) |
|
||||
|
||||
محتوای پیشنهادی بستهٔ پیشفرض در [preset-content.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:** خدمات دندانپزشکی مثل هر خدمت دیگری در سایت دیده میشوند.
|
||||
هیچ تغییر اختصاصی لازم نیست مگر اینکه بخواهیم انتخاب دندان در رزرو آنلاین باشد، که خارج از این سند است.
|
||||
Reference in New Issue
Block a user