- 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.
240 lines
17 KiB
Markdown
240 lines
17 KiB
Markdown
# ماژول دندانپزشکی 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:** خدمات دندانپزشکی مثل هر خدمت دیگری در سایت دیده میشوند.
|
||
هیچ تغییر اختصاصی لازم نیست مگر اینکه بخواهیم انتخاب دندان در رزرو آنلاین باشد، که خارج از این سند است.
|