feat(docs): add laser treatment plan and related ADRs for multi-session treatments
This commit is contained in:
@@ -0,0 +1,419 @@
|
|||||||
|
# طول درمان و پرونده درمان چندجلسهای (فاز اول: لیزر)
|
||||||
|
|
||||||
|
## پروژه
|
||||||
|
|
||||||
|
`clinicpro` (backend + پنل ادمین). هیچ تغییری در `nobat724_front` و `clinic-pro-tauri` لازم نیست.
|
||||||
|
|
||||||
|
## زمینه
|
||||||
|
|
||||||
|
این سند خروجی یک جلسه grilling است. ۲۳ تصمیم قفل شد، شش ADR و یک glossary نوشته شد.
|
||||||
|
پیش از شروع اینها را بخوان:
|
||||||
|
|
||||||
|
- `clinicpro/CONTEXT.md` — واژگان رسمی این دامنه
|
||||||
|
- `clinicpro/docs/adr/0001-treatment-sessions-are-not-appointments.md`
|
||||||
|
- `clinicpro/docs/adr/0002-treatment-areas-are-snapshotted.md`
|
||||||
|
- `clinicpro/docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md`
|
||||||
|
- `clinicpro/docs/adr/0004-session-parameters-are-json-keyed-by-resource-type.md`
|
||||||
|
- `clinicpro/docs/adr/0005-treatment-workflows-are-tagged-services.md`
|
||||||
|
- `clinicpro/docs/adr/0006-clinical-record-is-separate-from-the-visit-record.md`
|
||||||
|
- `clinicpro/docs/architecture/resource-first-model.md`
|
||||||
|
|
||||||
|
از واژگان `CONTEXT.md` استفاده کن. مترادف نساز.
|
||||||
|
|
||||||
|
## هدف
|
||||||
|
|
||||||
|
کلینیک بتواند سرویسی تعریف کند که درمانش چند جلسه طول میکشد، و سیستم برای هر بیمار
|
||||||
|
پرونده درمان بسازد، جلسات را بشمارد، سررسید جلسه بعد را حساب کند، و اپراتور بتواند
|
||||||
|
برای هر ناحیه بدن، دستگاه و پارامترهایش را ثبت کند.
|
||||||
|
|
||||||
|
فاز اول فقط لیزر. ولی هیچجای کد نباید کلمه «لیزر» را بداند، جز پیادهسازی workflow.
|
||||||
|
|
||||||
|
## آنچه از قبل هست و باید استفاده شود
|
||||||
|
|
||||||
|
| چیز | کجا | نکته |
|
||||||
|
|---|---|---|
|
||||||
|
| دستهبندی گرافی خدمات | `CatalogCategory` + `CatalogCategoryInclude` | نواحی بدن همینجا تعریف میشوند |
|
||||||
|
| بستار گذرا و تشخیص تعارض | `CategoryClosureResolver` | `descendants()` و `overlaps()` |
|
||||||
|
| سرویس | `ServiceItem` با `catalogCategory` | قیمت و مدت اینجاست |
|
||||||
|
| نوع منبع داینامیک | `ResourceType` | کدهای سیستمی `doctor` / `staff` / `room` |
|
||||||
|
| منبع با پزشک ناظر | `ClinicResource.supervisor` | تعریف شده ولی در مسیر رزرو خوانده نمیشود |
|
||||||
|
| اشغال منبع در سطح دیتابیس | `OccupancyBucket` | `uniq_bucket_resource_seat(resource_id, bucket_at, seat)` |
|
||||||
|
| پرسنل و نقش | `ClinicStaff` + `ROLE_STAFF` | `ClinicStaff.user` اختیاری است |
|
||||||
|
| داشبورد پرسنل | `GET /api/v1/dashboard/staff` | فیلتر روی `a.staff` |
|
||||||
|
| صفحه پرسنل | `assets/admin/pages/StaffMyServicesPage.tsx` | فقط سرویسهای تخصیصیافته |
|
||||||
|
| مراجعه مالی | `PatientSession` | در `AppointmentConfirmationService::onConfirmed` ساخته میشود |
|
||||||
|
|
||||||
|
## آنچه نیست
|
||||||
|
|
||||||
|
هیچ موجودیتی برای پرونده درمان، جلسه درمان، ثبت ناحیه، پروتکل، یا حوزه فعالیت.
|
||||||
|
`ServiceItem.sessionCount` هست ولی هیچ منطقی از آن استفاده نمیکند — عملاً مرده.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## تصمیمهای قفلشده
|
||||||
|
|
||||||
|
اینها در جلسه grilling تصمیمگیری شدهاند. اجرایشان کن، دوباره طراحی نکن.
|
||||||
|
اگر جایی از کد با یکی از اینها تناقض داشت، **متوقف شو و بپرس**؛ خودت تصمیم را عوض نکن.
|
||||||
|
|
||||||
|
1. **حوزه فعالیت از `Specialty` جداست.** `Specialty` قرارداد سایت عمومی است و دست نمیخورد.
|
||||||
|
2. **هر کلینیک یک حوزه فعالیت دارد.** نال یعنی تنظیمنشده و رفتار امروز.
|
||||||
|
3. **جلسه درمان موجودیت مستقل است**، نه `Appointment`.
|
||||||
|
4. **زمانبندی با لیست صریح گامها.** فاصله ثابت نداریم.
|
||||||
|
5. **دوره پایان مشخص دارد.** دوره بیپایان وجود ندارد.
|
||||||
|
6. **همه جلسات از ابتدا ساخته میشوند**، ولی فقط جلسه بعدی نوبت میگیرد.
|
||||||
|
7. **ناحیه درمان همان `CatalogCategory` است.** هیچ entity جدیدی برای ناحیه ساخته نشود.
|
||||||
|
8. **نواحی از دسته سرویس مشتق میشوند**، هنگام رزرو انتخاب نمیشوند.
|
||||||
|
9. **فهرست نواحی هنگام ساخت پرونده قفل میشود** (snapshot).
|
||||||
|
10. **پزشک ناظرِ منبع روی نوبت مینشیند.** پرسنل انجام میدهد.
|
||||||
|
11. **نوبتی که منبع دارد `active_slot_key` ندارد.** حفاظت فقط با `OccupancyBucket`.
|
||||||
|
12. **`TreatmentProtocol` موجودیت جداست**، یکبهیک با `ServiceItem`.
|
||||||
|
13. **پارامترهای دستگاه در JSON**، تعریفشان روی `ResourceType`.
|
||||||
|
14. **Workflow با tagged service.** موتور دادهمحور نداریم.
|
||||||
|
15. **حوزه فعالیت را فقط ادمین پلتفرم میسازد.**
|
||||||
|
16. **جلسه وضعیت مستقل دارد** و نوبت را همگام میکند. بستن جلسه با ناحیه ناتمام مجاز است.
|
||||||
|
17. **`TreatmentSession` بالینی است، `PatientSession` مالی.** هیچ فیلد پولی روی جلسه درمان.
|
||||||
|
18. **قیمت هر جلسه با قیمت روز.** پکیج قیمت نداریم. قیمت هیچوقت قفل نمیشود.
|
||||||
|
19. **جلسه بعد پیشنهاد میشود، منشی تأیید میکند.** رزرو خودکار بدون انسان نداریم.
|
||||||
|
20. **حوزه فعالیت فقط workflow را انتخاب میکند.** داشبورد اختصاصی بهازای تخصص نداریم.
|
||||||
|
21. **سررسید هر جلسه نسبی به تاریخ واقعی جلسه قبل است.**
|
||||||
|
22. **no-show جلسه را نمیسوزاند.** تعداد جلسات ثابت میماند.
|
||||||
|
23. **زمان واقعی جدا ثبت میشود.** `slotStart` و `slotEnd` هرگز بازنویسی نمیشوند.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## وظایف
|
||||||
|
|
||||||
|
هر وظیفه را جداگانه پیاده کن، تست بنویس، و بعد سراغ بعدی برو.
|
||||||
|
|
||||||
|
### ۱. حوزه فعالیت کلینیک
|
||||||
|
|
||||||
|
موجودیت جدید در `src/PracticeDomain/Entity/PracticeDomain.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// جدول سراسری (global) — نه per-tenant. در GlobalTables ثبت شود.
|
||||||
|
id, uuid, code (unique), name, sort_order, active, created_at, updated_at
|
||||||
|
```
|
||||||
|
|
||||||
|
`code` پایدار است و workflow به آن bind میشود. بعد از ساخت قابل ویرایش نیست.
|
||||||
|
|
||||||
|
روی `Clinic` یک `ManyToOne` نالپذیر اضافه کن:
|
||||||
|
|
||||||
|
```php
|
||||||
|
#[ORM\ManyToOne(targetEntity: PracticeDomain::class)]
|
||||||
|
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
||||||
|
private ?PracticeDomain $practiceDomain = null;
|
||||||
|
```
|
||||||
|
|
||||||
|
migration نباید مقدار پیشفرض برای کلینیکهای موجود بگذارد. نال بماند.
|
||||||
|
|
||||||
|
اندپوینتها:
|
||||||
|
|
||||||
|
- `GET /api/v1/practice-domains` — فهرست فعالها. برای همه نقشهای پنلی.
|
||||||
|
- `POST /api/v1/admin/practice-domains` — فقط `ROLE_ADMIN`.
|
||||||
|
- `PATCH /api/v1/admin/practice-domains/{uuid}` — فقط `name` و `active` و `sort_order`.
|
||||||
|
- `PATCH /api/v1/clinic/{uuid}/practice-domain` — مدیر کلینیک انتخاب میکند.
|
||||||
|
|
||||||
|
در پاسخ هر حوزه یک فیلد `has_workflow` بگذار که از `TreatmentWorkflowRegistry` میآید.
|
||||||
|
پنل ادمین پلتفرم باید بتواند نشان دهد کدام حوزه هنوز workflow ندارد.
|
||||||
|
|
||||||
|
seed اولیه با migration: `beauty` = «کلینیک زیبایی».
|
||||||
|
|
||||||
|
### ۲. پروتکل درمان
|
||||||
|
|
||||||
|
سه موجودیت در `src/Treatment/Entity/`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// TreatmentProtocol — وجود این ردیف یعنی سوییچ «طول درمان» روشن است
|
||||||
|
id, uuid, service_item_id (unique, ON DELETE CASCADE),
|
||||||
|
supervisor_doctor_id (nullable), active, created_at, updated_at
|
||||||
|
|
||||||
|
// TreatmentProtocolStep — گامهای دوره
|
||||||
|
id, protocol_id, step_number, offset_days, created_at
|
||||||
|
// UNIQUE(protocol_id, step_number)
|
||||||
|
// offset_days یعنی «فاصله از جلسهٔ قبل»، نه از شروع دوره. گام ۱ همیشه offset_days = 0.
|
||||||
|
|
||||||
|
// TreatmentProtocolStaff — پرسنل مجاز به انجام
|
||||||
|
id, protocol_id, staff_id
|
||||||
|
// UNIQUE(protocol_id, staff_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
قواعد اعتبارسنجی:
|
||||||
|
|
||||||
|
- حداقل دو گام. پروتکل یکجلسهای معنی ندارد؛ آن یعنی سوییچ خاموش.
|
||||||
|
- `step_number` پیوسته از ۱.
|
||||||
|
- گام اول `offset_days = 0`. بقیه بزرگتر از صفر.
|
||||||
|
- حداقل یک پرسنل مجاز.
|
||||||
|
- `supervisor_doctor_id` باید پزشکِ همان محیط باشد.
|
||||||
|
|
||||||
|
`ServiceItem::$sessionCount` را `@deprecated` علامت بزن، از `toArray()` بیرون **نبر**
|
||||||
|
(پنل و تایپ TS به آن وابستهاند) ولی هیچ منطق جدیدی از آن نخوان. تعداد جلسات
|
||||||
|
همیشه `count(protocol.steps)` است.
|
||||||
|
|
||||||
|
اندپوینتها زیر `/api/v1/clinic-services/{serviceUuid}/treatment-protocol`:
|
||||||
|
`GET`، `PUT` (کل پروتکل با گامها و پرسنل یکجا)، `DELETE` (خاموش کردن سوییچ).
|
||||||
|
|
||||||
|
### ۳. پرونده و جلسه درمان
|
||||||
|
|
||||||
|
```php
|
||||||
|
// TreatmentCase
|
||||||
|
id, uuid, entity_type, entity_id, // tenant
|
||||||
|
patient_record_id, service_item_id, protocol_id,
|
||||||
|
supervisor_doctor_id (nullable),
|
||||||
|
status, // active | completed | abandoned
|
||||||
|
total_sessions, // snapshot از تعداد گامها
|
||||||
|
opened_at, closed_at (nullable),
|
||||||
|
created_at, updated_at
|
||||||
|
|
||||||
|
// TreatmentCaseArea — snapshot نواحی (تصمیم ۹)
|
||||||
|
id, case_id, catalog_category_id, name_snapshot, sort_order
|
||||||
|
// UNIQUE(case_id, catalog_category_id)
|
||||||
|
|
||||||
|
// TreatmentSession
|
||||||
|
id, uuid, case_id, session_number,
|
||||||
|
appointment_id (nullable, ON DELETE SET NULL),
|
||||||
|
performed_by_staff_id (nullable), // تصمیم ۲۳
|
||||||
|
status, // planned | booked | in_progress | done | cancelled | no_show
|
||||||
|
due_at (nullable), // تخمینی، بعد از هر جلسه بازمحاسبه میشود
|
||||||
|
started_at (nullable), finished_at (nullable),
|
||||||
|
note (nullable),
|
||||||
|
created_at, updated_at
|
||||||
|
// UNIQUE(case_id, session_number)
|
||||||
|
|
||||||
|
// SessionAreaRecord
|
||||||
|
id, uuid, session_id, case_area_id,
|
||||||
|
resource_id (nullable), // دستگاه — در سطح ناحیه
|
||||||
|
status, // pending | in_progress | completed | skipped
|
||||||
|
parameters JSON (nullable), // { "energy": 18, "pulse": 3, "shots": 212 }
|
||||||
|
started_at (nullable), finished_at (nullable),
|
||||||
|
note (nullable),
|
||||||
|
created_at, updated_at
|
||||||
|
// UNIQUE(session_id, case_area_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
**هیچ ستون پولی روی این جدولها نگذار.** ADR-0006.
|
||||||
|
|
||||||
|
`name_snapshot` روی `TreatmentCaseArea` عمدی است: اگر مدیر بعداً اسم دسته را عوض کند،
|
||||||
|
سابقه درمان نباید تغییر کند.
|
||||||
|
|
||||||
|
نواحی هنگام ساخت پرونده اینطور حساب میشوند:
|
||||||
|
|
||||||
|
```
|
||||||
|
leaves = برگهای CategoryClosureResolver::descendants(service.catalogCategory)
|
||||||
|
اگر descendants خالی بود → خودِ service.catalogCategory تنها ناحیه است
|
||||||
|
```
|
||||||
|
|
||||||
|
«برگ» یعنی دستهای که خودش `descendants` ندارد. دستههای میانی فقط گروهبندیاند و
|
||||||
|
ناحیه درمان نیستند.
|
||||||
|
|
||||||
|
### ۴. اتصال پزشک ناظر به مسیر رزرو
|
||||||
|
|
||||||
|
در `AppointmentController` بلوکی که پزشک را از منبع استنتاج میکند (حدود خط ۴۷۱)
|
||||||
|
یک fallback اضافه کن:
|
||||||
|
|
||||||
|
```php
|
||||||
|
if ($doctorUuid === '' && $resource->subject() instanceof Doctor) {
|
||||||
|
$doctorUuid = $resource->subject()->getUuid();
|
||||||
|
}
|
||||||
|
// جدید:
|
||||||
|
if ($doctorUuid === '' && $resource->getSupervisor() !== null) {
|
||||||
|
$doctorUuid = $resource->getSupervisor()->getUuid();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
اگر منبعی نه پزشک است نه ناظر دارد، خطای واضح بده:
|
||||||
|
«این منبع پزشک ناظر ندارد؛ ابتدا در تنظیمات منابع پزشک ناظر را مشخص کنید».
|
||||||
|
پیام فعلی (`doctor_uuid یا resource_uuid ...`) گمراهکننده است.
|
||||||
|
|
||||||
|
### ۵. آزادسازی کلید اسلات برای نوبتهای منبعدار
|
||||||
|
|
||||||
|
در `Appointment::refreshActiveSlotKey()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$this->activeSlotKey = (!$this->isReserve
|
||||||
|
&& $this->resource === null // ← شرط جدید
|
||||||
|
&& in_array($this->status, self::SLOT_OCCUPYING_STATUSES, true))
|
||||||
|
? sprintf('%d:%d', $this->doctor->getId(), $this->slotStart)
|
||||||
|
: null;
|
||||||
|
```
|
||||||
|
|
||||||
|
`setResource()` باید `refreshActiveSlotKey()` را صدا بزند، وگرنه نوبتی که اول ساخته
|
||||||
|
و بعد منبعش ست میشود کلیدش باقی میماند.
|
||||||
|
|
||||||
|
**قبل از این تغییر:** همه مسیرهای ساخت نوبت را فهرست کن و مشخص کن کدامها `resource`
|
||||||
|
ست نمیکنند. آنها بعد از این تغییر همچنان با کلید پزشک محافظت میشوند — این درست است،
|
||||||
|
ولی باید مستند شود که کدامها هستند. ADR-0003 روی همین هشدار داده.
|
||||||
|
|
||||||
|
migration لازم نیست؛ ستون بدون تغییر میماند و فقط منطق پرشدنش عوض میشود.
|
||||||
|
|
||||||
|
### ۶. تعریف فیلد روی نوع منبع
|
||||||
|
|
||||||
|
ستون JSON روی `ResourceType`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
#[ORM\Column(name: 'field_schema', type: 'json', nullable: true)]
|
||||||
|
private ?array $fieldSchema = null;
|
||||||
|
```
|
||||||
|
|
||||||
|
قالب هر فیلد:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "key": "energy", "label": "انرژی", "type": "select",
|
||||||
|
"options": [7, 8, 9, 10, 12, 14, 16, 18], "required": true, "sort_order": 1 }
|
||||||
|
```
|
||||||
|
|
||||||
|
`type` مجاز: `select` و `number` و `text`. همین سه تا، نه بیشتر.
|
||||||
|
|
||||||
|
اعتبارسنجی مقادیر `SessionAreaRecord.parameters` از همین schema میآید. یک سرویس
|
||||||
|
`FieldSchemaValidator` بنویس که هم در ذخیره اندپوینت استفاده شود هم در تست.
|
||||||
|
|
||||||
|
کلیدهای ناشناخته که در schema نیستند رد شوند، نه اینکه بیصدا ذخیره شوند.
|
||||||
|
|
||||||
|
seed اولیه: یک `ResourceType` با کد `laser_device` و نام «دستگاه لیزر» و همان سه فیلد
|
||||||
|
بالا بهعلاوه `shots` از نوع `number`. `is_system = false` تا مدیر بتواند ویرایشش کند.
|
||||||
|
|
||||||
|
### ۷. Workflow قابل توسعه
|
||||||
|
|
||||||
|
```php
|
||||||
|
// src/Treatment/Workflow/TreatmentWorkflow.php
|
||||||
|
#[AutoconfigureTag('app.treatment_workflow')]
|
||||||
|
interface TreatmentWorkflow
|
||||||
|
{
|
||||||
|
public function supports(?string $practiceDomainCode): bool;
|
||||||
|
|
||||||
|
/** بعد از تأیید اولین نوبتِ یک سرویسِ پروتکلدار */
|
||||||
|
public function openCase(Appointment $appointment, TreatmentProtocol $protocol): TreatmentCase;
|
||||||
|
|
||||||
|
/** بعد از بسته شدن یک جلسه — سررسید جلسه بعد را حساب میکند */
|
||||||
|
public function onSessionFinished(TreatmentSession $session): void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`TreatmentWorkflowRegistry` با `#[TaggedIterator('app.treatment_workflow')]` ساخته شود و
|
||||||
|
اولین workflow ای که `supports()` بدهد را برگرداند. اگر هیچکدام، `DefaultTreatmentWorkflow`
|
||||||
|
که رفتار عمومی دارد.
|
||||||
|
|
||||||
|
**هسته نباید بداند لیزر چیست.** `AppointmentConfirmationService` فقط این را میکند:
|
||||||
|
|
||||||
|
```
|
||||||
|
اگر سرویسِ نوبت پروتکل فعال دارد و بیمار پروندهٔ باز برای همان سرویس ندارد
|
||||||
|
→ registry->for(clinic.practiceDomain?.code)->openCase(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
`LaserTreatmentWorkflow` در فاز اول تقریباً همان `DefaultTreatmentWorkflow` است.
|
||||||
|
جدا نگهش دار حتی اگر خالی باشد — نقطه اتصال آینده است.
|
||||||
|
|
||||||
|
### ۸. سررسید و جلسه بعد
|
||||||
|
|
||||||
|
قاعده محاسبه (تصمیم ۲۱):
|
||||||
|
|
||||||
|
```
|
||||||
|
due_at(session n) = finished_at(session n-1) + protocol.step[n].offset_days
|
||||||
|
جلسه ۱ سررسید ندارد؛ تاریخش همان نوبت اول است.
|
||||||
|
```
|
||||||
|
|
||||||
|
بعد از `finished_at` شدن هر جلسه، فقط `due_at` **جلسه بعدی** بازمحاسبه شود، نه کل دوره.
|
||||||
|
جلسات دورتر تخمین قبلیشان را نگه میدارند تا نوبتشان برسد.
|
||||||
|
|
||||||
|
no-show (تصمیم ۲۲): جلسه به `no_show` میرود، `session_number` عوض نمیشود،
|
||||||
|
`total_sessions` عوض نمیشود. یک جلسه جایگزین با همان شماره **ساخته نمیشود**؛ همان جلسه
|
||||||
|
دوباره به `planned` برمیگردد و `due_at` از تاریخ جلسه قبلِ **انجامشده** حساب میشود.
|
||||||
|
|
||||||
|
رزرو جلسه بعد (تصمیم ۱۹) **خودکار نیست**. اندپوینت پیشنهاد بده:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/treatment-sessions/{uuid}/slot-suggestions
|
||||||
|
→ اسلاتهای آزاد منبع، از due_at به بعد، با استفاده از ResourceFreeTimeCalculator
|
||||||
|
```
|
||||||
|
|
||||||
|
منشی یکی را انتخاب میکند و مسیر عادی ساخت نوبت اجرا میشود، سپس نوبت به جلسه وصل میشود.
|
||||||
|
|
||||||
|
### ۹. اندپوینتهای اجرای جلسه
|
||||||
|
|
||||||
|
همه زیر `ROLE_STAFF` یا بالاتر. علاوه بر نقش، بررسی کن پرسنل واقعاً به این جلسه دسترسی
|
||||||
|
دارد — الگویش در `DashboardController::staff` هست (`findActiveByUserAndEntity`).
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/dashboard/staff/treatment-sessions جلسات امروز پرسنل
|
||||||
|
GET /api/v1/treatment-sessions/{uuid} جزئیات + نواحی + فیلدهای دستگاه
|
||||||
|
POST /api/v1/treatment-sessions/{uuid}/start → in_progress، started_at
|
||||||
|
POST /api/v1/treatment-sessions/{uuid}/finish → done، finished_at، note
|
||||||
|
POST /api/v1/session-areas/{uuid}/start → in_progress، started_at
|
||||||
|
POST /api/v1/session-areas/{uuid}/complete → completed، parameters، finished_at
|
||||||
|
POST /api/v1/session-areas/{uuid}/skip → skipped
|
||||||
|
GET /api/v1/treatment-cases فهرست پروندهها با فیلتر
|
||||||
|
GET /api/v1/treatment-cases/{uuid} پرونده + همه جلسات
|
||||||
|
```
|
||||||
|
|
||||||
|
همگامسازی وضعیت نوبت (تصمیم ۱۶):
|
||||||
|
|
||||||
|
```
|
||||||
|
session start → Appointment::STATUS_SALON
|
||||||
|
session finish → Appointment::STATUS_COMPLETED
|
||||||
|
```
|
||||||
|
|
||||||
|
از `ALLOWED_TRANSITIONS` عبور کن، مستقیم `setStatus` نزن. اگر گذار مجاز نبود، جلسه را
|
||||||
|
ببند ولی نوبت را دست نزن و لاگ بگذار — خطای ۵۰۰ نده.
|
||||||
|
|
||||||
|
بستن جلسه با ناحیه ناتمام **مجاز است** (تصمیم ۱۶). فقط در پاسخ تعداد ناتمامها را برگردان
|
||||||
|
تا پنل هشدار نشان دهد.
|
||||||
|
|
||||||
|
`started_at` و `finished_at` هرگز روی `Appointment` نوشته نشوند (تصمیم ۲۳).
|
||||||
|
|
||||||
|
### ۱۰. پنل ادمین
|
||||||
|
|
||||||
|
قواعد اجباری این پروژه:
|
||||||
|
|
||||||
|
- هر `select` باید `components/ui/SearchableSelect` باشد. `<select>` بومی ممنوع.
|
||||||
|
- هر بولین باید `components/ui/Switch` باشد. checkbox بومی ممنوع.
|
||||||
|
- صفحه جدید با تم و Layout و کامپوننتهای موجود ساخته شود. طراحی جدید نکن.
|
||||||
|
- تاریخها شمسی. متنها فارسی. RTL.
|
||||||
|
|
||||||
|
صفحهها و تغییرها:
|
||||||
|
|
||||||
|
1. **فرم سرویس** — سوییچ «طول درمان». روشن که شد: جدول گامها (شماره و فاصله از جلسه قبل)،
|
||||||
|
`SearchableSelect` چندتایی پرسنل مجاز، `SearchableSelect` پزشک ناظر.
|
||||||
|
2. **تنظیمات کلینیک** — `SearchableSelect` حوزه فعالیت.
|
||||||
|
3. **صفحه نوع منابع** — ویرایشگر `fieldSchema`. افزودن و حذف فیلد، انتخاب نوع، گزینهها.
|
||||||
|
4. **پنل ادمین پلتفرم** — CRUD حوزههای فعالیت با نشان «workflow دارد / ندارد».
|
||||||
|
5. **فهرست پروندههای درمان** — نام بیمار، سرویس، جلسه چندم از چند، وضعیت، سررسید بعدی، اپراتور.
|
||||||
|
6. **صفحه اجرای جلسه** — کارت هر ناحیه با دکمه شروع، تایمر زنده، فرم داینامیک از `fieldSchema`،
|
||||||
|
دکمه اتمام ناحیه، دکمه لغو ناحیه. پایین صفحه یادداشت کلی و دکمه اتمام جلسه با هشدار
|
||||||
|
نواحی ناتمام. اسکرینشاتهای مرجع در تیکت این کار هست.
|
||||||
|
7. **صف «جلسات بدون نوبت»** — جلساتی که `status = planned` و `due_at` گذشته یا نزدیک است.
|
||||||
|
از هر ردیف مستقیم به انتخاب اسلات پیشنهادی.
|
||||||
|
|
||||||
|
تایمر فقط نمایشی است. زمان معتبر همان `started_at` و `finished_at` سرور است.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ترتیب اجرا
|
||||||
|
|
||||||
|
```
|
||||||
|
۱ → ۲ → ۳ → ۶ → ۷ → ۴ → ۵ → ۸ → ۹ → ۱۰
|
||||||
|
```
|
||||||
|
|
||||||
|
وظیفه ۵ (کلید اسلات) روی پرترافیکترین جدول سیستم است. بعد از وظیفه ۴ انجامش بده و
|
||||||
|
قبل و بعدش تست رگرسیون رزرو را کامل اجرا کن.
|
||||||
|
|
||||||
|
## تست
|
||||||
|
|
||||||
|
- unit برای `CategoryClosureResolver` در حالت برگیابی نواحی
|
||||||
|
- unit برای محاسبه `due_at` با گامهای نامساوی (سناریوی بوتاکس: ۰، ۱۵، ۳۰، ۳۰)
|
||||||
|
- unit برای `FieldSchemaValidator` با کلید ناشناخته و مقدار خارج از `options`
|
||||||
|
- functional: پزشک ناظر مشترک بین دو دستگاه، دو رزرو همساعت، هر دو باید موفق شوند
|
||||||
|
- functional: اتاق با `capacity = 3`، سه رزرو همساعت، هر سه باید موفق شوند
|
||||||
|
- functional: چرخه کامل یک دوره سهجلسهای شامل یک no-show
|
||||||
|
- رگرسیون: رزرو بدون منبع همچنان با کلید پزشک از دوبار رزرو جلوگیری کند
|
||||||
|
|
||||||
|
## خارج از دامنه فاز اول
|
||||||
|
|
||||||
|
- seeder هوشمند با AI برای پیشنهاد دستهبندی و منابع
|
||||||
|
- گزارشهای تحلیلی روی `parameters` (کوئری JSON بدون ایندکس)
|
||||||
|
- حوزه فعالیت دوم غیر از زیبایی
|
||||||
|
- داشبورد اختصاصی بهازای هر تخصص
|
||||||
|
- قیمت پکیج و قفل قیمت
|
||||||
|
|
||||||
|
## مستندسازی
|
||||||
|
|
||||||
|
طبق قانون ثابت این پروژه، `docs/api/*` در همان session بهروز شود.
|
||||||
|
اگر تصمیمی در حین اجرا عوض شد، ADR مربوطه بهروز شود یا ADR جدید نوشته شود.
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
# ClinicPro Backend
|
||||||
|
|
||||||
|
The Symfony API and bundled React admin that owns all clinic data, scheduling and auth for the
|
||||||
|
ClinicPro product. This glossary records the language the backend uses for its own concepts.
|
||||||
|
|
||||||
|
## Language
|
||||||
|
|
||||||
|
### Clinic configuration
|
||||||
|
|
||||||
|
**Practice Domain**:
|
||||||
|
The single field of practice a clinic declares it operates in — beauty, dental, orthopaedics. It is a
|
||||||
|
configuration key: it selects which dashboard, forms and treatment workflows the clinic gets. A
|
||||||
|
clinic has exactly one.
|
||||||
|
_Avoid_: Specialty, clinic type, field, discipline
|
||||||
|
|
||||||
|
**Specialty**:
|
||||||
|
A medical specialty label attached to a Clinic or a Doctor, used by the public booking site for
|
||||||
|
listing and SEO. It is descriptive, not configuration — it never selects behaviour.
|
||||||
|
_Avoid_: Practice Domain, category
|
||||||
|
|
||||||
|
### Treatment
|
||||||
|
|
||||||
|
**Treatment Protocol**:
|
||||||
|
The template attached to a service that says a course of that service runs over several sessions, when
|
||||||
|
each one falls due, which doctor supervises the course, and which staff are allowed to perform it.
|
||||||
|
Defined once by the clinic manager, not per patient.
|
||||||
|
_Avoid_: Treatment plan, course template, session config
|
||||||
|
|
||||||
|
**Supervising Doctor**:
|
||||||
|
The doctor answerable for a Treatment Protocol and for every Treatment Case opened from it. They carry
|
||||||
|
clinical responsibility; they do not necessarily perform the treatment.
|
||||||
|
_Avoid_: Doctor, owner, responsible
|
||||||
|
|
||||||
|
**Operator**:
|
||||||
|
The staff member who actually performs a Treatment Session — runs the device, treats each area, and
|
||||||
|
records what was done. Chosen at booking time from the staff the Treatment Protocol allows.
|
||||||
|
_Avoid_: Technician, performer, staff, nurse
|
||||||
|
|
||||||
|
**Treatment Case**:
|
||||||
|
One patient's run of a Treatment Protocol, from the first booking until the course ends. It owns the
|
||||||
|
sessions and carries the state of the whole course.
|
||||||
|
_Avoid_: Treatment plan, patient file, dossier, episode
|
||||||
|
|
||||||
|
**Treatment Session**:
|
||||||
|
One numbered step of a Treatment Case — session 3 of 8. It exists whether or not it has been booked
|
||||||
|
yet, so its number survives cancellation and rescheduling. It holds the plan and the clinical record,
|
||||||
|
never money.
|
||||||
|
_Avoid_: Appointment, visit, session slot, patient session
|
||||||
|
|
||||||
|
**Visit Record**:
|
||||||
|
The billing side of one attended visit — services rendered, insurance shares, discounts, payments. It
|
||||||
|
comes into existence when an Appointment is confirmed, so a Treatment Session that has not been booked
|
||||||
|
yet has none.
|
||||||
|
_Avoid_: Session, invoice, patient session
|
||||||
|
|
||||||
|
**Appointment**:
|
||||||
|
A reserved slot in a calendar. It is the booking, not the treatment. A Treatment Session may point at
|
||||||
|
one, at a different one after rescheduling, or at none while still unbooked.
|
||||||
|
_Avoid_: Session, booking, reservation
|
||||||
|
|
||||||
|
**Treatment Area**:
|
||||||
|
A region of the body a Treatment Session is performed on — underarms, bikini line. A single session
|
||||||
|
covers several, each completed and recorded on its own.
|
||||||
|
_Avoid_: Zone, body part, region
|
||||||
|
|
||||||
|
**Session Area Record**:
|
||||||
|
What the operator actually did to one Treatment Area in one Treatment Session — the device used, the
|
||||||
|
parameters it was set to, how long it took, and any note.
|
||||||
|
_Avoid_: Treatment log, area result, shot record
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Treatment Sessions are separate from Appointments
|
||||||
|
|
||||||
|
Multi-session treatments (laser courses, botox top-ups) need a session that keeps its number and its
|
||||||
|
clinical record across cancellations and reschedules, and they must not lock eight months of calendar
|
||||||
|
slots the moment a course starts. So a Treatment Session is its own record owning the clinical data,
|
||||||
|
holding an optional reference to an Appointment; booking a session creates the Appointment, and
|
||||||
|
rescheduling swaps it without disturbing the session.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
Making the Appointment itself the session was rejected: session numbering would break on every
|
||||||
|
cancellation, and pre-creating every future session as a real Appointment would occupy slots months
|
||||||
|
ahead for patients who may never attend.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# A Treatment Case snapshots its areas
|
||||||
|
|
||||||
|
The areas a service covers are derived from the catalog category graph, which the clinic manager can
|
||||||
|
edit at any time. Because a session's area records are a medical record, a Treatment Case copies its
|
||||||
|
area list at creation and never re-derives it; editing the category graph afterwards affects only
|
||||||
|
cases opened from then on.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
An in-flight case will not pick up a category change. If a clinic genuinely needs that, it has to be
|
||||||
|
an explicit re-sync action, not a silent side effect of editing settings.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Resource-backed appointments are guarded by occupancy, not the doctor slot key
|
||||||
|
|
||||||
|
An appointment's `active_slot_key` is `doctor_id:slot_start` under a unique index, which assumes the
|
||||||
|
doctor is the thing being occupied. Once a doctor supervises several devices that assumption breaks:
|
||||||
|
the second booking in the same hour on a different device is rejected. Resource occupancy already
|
||||||
|
guards those bookings at the database level via `uniq_bucket_resource_seat (resource_id, bucket_at,
|
||||||
|
seat)`, so an appointment that carries a resource leaves `active_slot_key` null and lets occupancy be
|
||||||
|
the sole authority; only resourceless legacy bookings keep the doctor key.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
Rekeying on the resource (`r{resource_id}:{slot_start}`) was rejected because it silently defeats
|
||||||
|
`ClinicResource.capacity`: a room seating three would reject its second patient, and the unique index
|
||||||
|
knows nothing about seats, buffers, or setup and cleanup time.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
Any booking path that omits the resource falls back to the doctor key. Those paths have to be found
|
||||||
|
and made resource-aware, or they end up with weaker protection than they have today.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Session parameters are JSON, described by the resource type
|
||||||
|
|
||||||
|
What an operator records for a treated area splits in two: facts every specialty shares — which
|
||||||
|
resource, when it started and finished, the note — and readings that belong to one kind of device,
|
||||||
|
like a laser's energy, pulse and shot count. The shared facts are real columns on the session's area
|
||||||
|
record; the device-specific readings live in a `parameters` JSON column, and the field list that
|
||||||
|
drives the form and its validation is declared on the resource type. Adding a dentistry or RF device
|
||||||
|
is then a settings change, not a migration.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
Aggregate reporting over a JSON key (average energy per area over a quarter) has no index behind it
|
||||||
|
and will be slow. If such a report becomes a first-class requirement, the specific keys get promoted
|
||||||
|
to real columns rather than the whole design being reversed.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Treatment workflows are tagged services, not a configurable engine
|
||||||
|
|
||||||
|
Everything that differs between specialties as *data* — categories, protocol steps, resource types,
|
||||||
|
form fields — is already stored as data. What is left is behaviour: when a case opens, what happens
|
||||||
|
when a session completes. That is expressed as a `TreatmentWorkflow` interface with one
|
||||||
|
implementation per practice domain, resolved through a Symfony tagged-service registry, so booking
|
||||||
|
code never names a specialty and a new one is a new class rather than a core change.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
A data-driven state machine editable by clinic managers was rejected: no clinic manager will author a
|
||||||
|
state machine, so in practice only developers would use it — code with worse syntax, no type safety
|
||||||
|
and no debugger.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# The clinical record of a session is separate from its visit record
|
||||||
|
|
||||||
|
`PatientSession` already means "an attended visit that gets billed" — it is created when an
|
||||||
|
Appointment is confirmed and owns services, insurance shares, discounts and payments. A Treatment
|
||||||
|
Session, by contrast, exists from the moment a course is planned, long before any booking, and must
|
||||||
|
survive reschedules. So the two stay separate: a Treatment Session holds the plan and the clinical
|
||||||
|
record (its area records, devices and readings) and carries no money, while the Visit Record keeps
|
||||||
|
the financial side and is reached through the Appointment.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
A session's full picture spans four records — case, session, appointment, visit — so queries are
|
||||||
|
longer. In exchange, neither side can silently become a second source of truth for the other. Any
|
||||||
|
money field appearing on a Treatment Session is a design error.
|
||||||
@@ -1315,17 +1315,30 @@
|
|||||||
"1313": "Community 1313",
|
"1313": "Community 1313",
|
||||||
"1314": "Community 1314",
|
"1314": "Community 1314",
|
||||||
"1315": "Community 1315",
|
"1315": "Community 1315",
|
||||||
|
"1316": "Community 1316",
|
||||||
"1317": "Community 1317",
|
"1317": "Community 1317",
|
||||||
|
"1318": "Community 1318",
|
||||||
"1319": "Community 1319",
|
"1319": "Community 1319",
|
||||||
"1320": "Community 1320",
|
"1320": "Community 1320",
|
||||||
"1321": "Community 1321",
|
"1321": "Community 1321",
|
||||||
|
"1322": "Community 1322",
|
||||||
|
"1323": "Community 1323",
|
||||||
|
"1324": "Community 1324",
|
||||||
|
"1325": "Community 1325",
|
||||||
|
"1326": "Community 1326",
|
||||||
"1327": "Community 1327",
|
"1327": "Community 1327",
|
||||||
"1328": "Community 1328",
|
"1328": "Community 1328",
|
||||||
"1329": "Community 1329",
|
"1329": "Community 1329",
|
||||||
"1330": "Community 1330",
|
"1330": "Community 1330",
|
||||||
"1331": "Community 1331",
|
"1331": "Community 1331",
|
||||||
|
"1332": "Community 1332",
|
||||||
|
"1333": "Community 1333",
|
||||||
"1334": "Community 1334",
|
"1334": "Community 1334",
|
||||||
"1335": "Community 1335",
|
"1335": "Community 1335",
|
||||||
|
"1336": "Community 1336",
|
||||||
|
"1337": "Community 1337",
|
||||||
|
"1338": "Community 1338",
|
||||||
|
"1339": "Community 1339",
|
||||||
"1340": "Community 1340",
|
"1340": "Community 1340",
|
||||||
"1341": "Community 1341",
|
"1341": "Community 1341",
|
||||||
"1342": "Community 1342",
|
"1342": "Community 1342",
|
||||||
@@ -1336,33 +1349,70 @@
|
|||||||
"1347": "Community 1347",
|
"1347": "Community 1347",
|
||||||
"1348": "Community 1348",
|
"1348": "Community 1348",
|
||||||
"1349": "Community 1349",
|
"1349": "Community 1349",
|
||||||
|
"1350": "Community 1350",
|
||||||
"1351": "Community 1351",
|
"1351": "Community 1351",
|
||||||
|
"1352": "Community 1352",
|
||||||
|
"1353": "Community 1353",
|
||||||
"1354": "Community 1354",
|
"1354": "Community 1354",
|
||||||
"1355": "Community 1355",
|
"1355": "Community 1355",
|
||||||
|
"1356": "Community 1356",
|
||||||
|
"1357": "Community 1357",
|
||||||
|
"1358": "Community 1358",
|
||||||
"1359": "Community 1359",
|
"1359": "Community 1359",
|
||||||
"1360": "Community 1360",
|
"1360": "Community 1360",
|
||||||
|
"1361": "Community 1361",
|
||||||
"1362": "Community 1362",
|
"1362": "Community 1362",
|
||||||
|
"1363": "Community 1363",
|
||||||
|
"1364": "Community 1364",
|
||||||
"1365": "Community 1365",
|
"1365": "Community 1365",
|
||||||
|
"1366": "Community 1366",
|
||||||
"1367": "Community 1367",
|
"1367": "Community 1367",
|
||||||
"1368": "Community 1368",
|
"1368": "Community 1368",
|
||||||
|
"1369": "Community 1369",
|
||||||
|
"1370": "Community 1370",
|
||||||
|
"1371": "Community 1371",
|
||||||
|
"1372": "Community 1372",
|
||||||
"1373": "Community 1373",
|
"1373": "Community 1373",
|
||||||
|
"1374": "Community 1374",
|
||||||
|
"1375": "Community 1375",
|
||||||
"1376": "Community 1376",
|
"1376": "Community 1376",
|
||||||
|
"1377": "Community 1377",
|
||||||
|
"1378": "Community 1378",
|
||||||
"1379": "Community 1379",
|
"1379": "Community 1379",
|
||||||
|
"1380": "Community 1380",
|
||||||
"1381": "Community 1381",
|
"1381": "Community 1381",
|
||||||
|
"1382": "Community 1382",
|
||||||
"1383": "Community 1383",
|
"1383": "Community 1383",
|
||||||
"1384": "Community 1384",
|
"1384": "Community 1384",
|
||||||
|
"1385": "Community 1385",
|
||||||
"1386": "Community 1386",
|
"1386": "Community 1386",
|
||||||
|
"1387": "Community 1387",
|
||||||
|
"1388": "Community 1388",
|
||||||
|
"1389": "Community 1389",
|
||||||
"1390": "Community 1390",
|
"1390": "Community 1390",
|
||||||
|
"1391": "Community 1391",
|
||||||
"1392": "Community 1392",
|
"1392": "Community 1392",
|
||||||
"1393": "Community 1393",
|
"1393": "Community 1393",
|
||||||
"1394": "Community 1394",
|
"1394": "Community 1394",
|
||||||
"1395": "Community 1395",
|
"1395": "Community 1395",
|
||||||
"1396": "Community 1396",
|
"1396": "Community 1396",
|
||||||
"1397": "Community 1397",
|
"1397": "Community 1397",
|
||||||
|
"1398": "Community 1398",
|
||||||
|
"1399": "Community 1399",
|
||||||
|
"1400": "Community 1400",
|
||||||
"1401": "Community 1401",
|
"1401": "Community 1401",
|
||||||
"1402": "Community 1402",
|
"1402": "Community 1402",
|
||||||
|
"1403": "Community 1403",
|
||||||
|
"1404": "Community 1404",
|
||||||
|
"1405": "Community 1405",
|
||||||
"1406": "Community 1406",
|
"1406": "Community 1406",
|
||||||
"1407": "Community 1407",
|
"1407": "Community 1407",
|
||||||
|
"1408": "Community 1408",
|
||||||
|
"1409": "Community 1409",
|
||||||
|
"1410": "Community 1410",
|
||||||
|
"1411": "Community 1411",
|
||||||
|
"1412": "Community 1412",
|
||||||
|
"1413": "Community 1413",
|
||||||
"1414": "Community 1414",
|
"1414": "Community 1414",
|
||||||
"1415": "Community 1415",
|
"1415": "Community 1415",
|
||||||
"1416": "Community 1416",
|
"1416": "Community 1416",
|
||||||
@@ -1371,18 +1421,33 @@
|
|||||||
"1419": "Community 1419",
|
"1419": "Community 1419",
|
||||||
"1420": "Community 1420",
|
"1420": "Community 1420",
|
||||||
"1421": "Community 1421",
|
"1421": "Community 1421",
|
||||||
|
"1422": "Community 1422",
|
||||||
|
"1423": "Community 1423",
|
||||||
|
"1424": "Community 1424",
|
||||||
"1425": "Community 1425",
|
"1425": "Community 1425",
|
||||||
"1426": "Community 1426",
|
"1426": "Community 1426",
|
||||||
|
"1427": "Community 1427",
|
||||||
|
"1428": "Community 1428",
|
||||||
|
"1429": "Community 1429",
|
||||||
|
"1430": "Community 1430",
|
||||||
"1431": "Community 1431",
|
"1431": "Community 1431",
|
||||||
"1432": "Community 1432",
|
"1432": "Community 1432",
|
||||||
|
"1433": "Community 1433",
|
||||||
|
"1434": "Community 1434",
|
||||||
|
"1435": "Community 1435",
|
||||||
"1436": "Community 1436",
|
"1436": "Community 1436",
|
||||||
|
"1437": "Community 1437",
|
||||||
|
"1438": "Community 1438",
|
||||||
"1439": "Community 1439",
|
"1439": "Community 1439",
|
||||||
"1440": "Community 1440",
|
"1440": "Community 1440",
|
||||||
|
"1441": "Community 1441",
|
||||||
"1442": "Community 1442",
|
"1442": "Community 1442",
|
||||||
|
"1443": "Community 1443",
|
||||||
|
"1444": "Community 1444",
|
||||||
|
"1445": "Community 1445",
|
||||||
"1447": "Community 1447",
|
"1447": "Community 1447",
|
||||||
"1452": "Community 1452",
|
"1452": "Community 1452",
|
||||||
"1453": "Community 1453",
|
"1453": "Community 1453",
|
||||||
"1457": "Community 1457",
|
"1457": "Community 1457",
|
||||||
"1462": "Community 1462",
|
|
||||||
"1475": "Community 1475"
|
"1475": "Community 1475"
|
||||||
}
|
}
|
||||||
|
|||||||
+459
-210
File diff suppressed because it is too large
Load Diff
graphify-out/cache/ast/v0.8.44/072154a8b4bc4a968e659476940a33181d7a472a3b45421089180aae50bb7479.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/0bebfa0dce3d5fdfa58447295507924b71b0875c9f790e7af75a0332c5597f2a.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/0dd012ebdbe31aa55aa576bca27bf7fd6bcd4d10f2b4b1807f0285b598619119.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/1c46cb110a9b2c8ae17db70da9f020d6bb10fda30a2df2524ab5970b8bb25495.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/1c4ea68ad641c6e0e9374579c819d136562c1d65aeb1b0d7739b1267b903a329.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/1d0433d8ee8a586d37b5d7a03817a221b5af939978a1af55b4b486dcb2100fa1.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/1d6fb0164c52de51c38f6f9189e601df655337e8677b6096d872c2332506652b.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/205a0404e878c6605ef02a79c7be6e556db147ca6639e20f8d162cab62dd8efe.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/25641224fa2513a1b7e1d66f460b8ac3d279322a4520d80e0e6ec6fe1e1535db.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/282420f28443c29d777191f6cb21d0d40d3a91078a5f02a49baf42a1d6a859b9.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0001_treatment_sessions_are_not_appointments_md", "label": "0001-treatment-sessions-are-not-appointments.md", "file_type": "document", "source_file": "docs/adr/0001-treatment-sessions-are-not-appointments.md", "source_location": "L1"}, {"id": "adr_0001_treatment_sessions_are_not_appointments_treatment_sessions_are_separate_from_appointments", "label": "Treatment Sessions are separate from Appointments", "file_type": "document", "source_file": "docs/adr/0001-treatment-sessions-are-not-appointments.md", "source_location": "L1"}, {"id": "adr_0001_treatment_sessions_are_not_appointments_considered_options", "label": "Considered Options", "file_type": "document", "source_file": "docs/adr/0001-treatment-sessions-are-not-appointments.md", "source_location": "L9"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0001_treatment_sessions_are_not_appointments_md", "target": "adr_0001_treatment_sessions_are_not_appointments_treatment_sessions_are_separate_from_appointments", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0001-treatment-sessions-are-not-appointments.md", "source_location": "L1", "weight": 1.0}, {"source": "adr_0001_treatment_sessions_are_not_appointments_treatment_sessions_are_separate_from_appointments", "target": "adr_0001_treatment_sessions_are_not_appointments_considered_options", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0001-treatment-sessions-are-not-appointments.md", "source_location": "L9", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/2a2d6aa142a13fc6868c5501e8dec6d65f20ab9f796a08008ff56132a9a6bb50.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/2f215af3e38682233f73a5c578dc0cc9084bbe4a14ff3ae46c1f4b8aa4cbd2e2.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/38c577432061de325941f2a2e67c3c86d5ebb3d18516a875ae3204c571fbcb8e.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_context_md", "label": "CONTEXT.md", "file_type": "document", "source_file": "CONTEXT.md", "source_location": "L1"}, {"id": "clinicpro_context_clinicpro_backend", "label": "ClinicPro Backend", "file_type": "document", "source_file": "CONTEXT.md", "source_location": "L1"}, {"id": "clinicpro_context_language", "label": "Language", "file_type": "document", "source_file": "CONTEXT.md", "source_location": "L6"}, {"id": "clinicpro_context_clinic_configuration", "label": "Clinic configuration", "file_type": "document", "source_file": "CONTEXT.md", "source_location": "L8"}, {"id": "clinicpro_context_treatment", "label": "Treatment", "file_type": "document", "source_file": "CONTEXT.md", "source_location": "L21"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_context_md", "target": "clinicpro_context_clinicpro_backend", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CONTEXT.md", "source_location": "L1", "weight": 1.0}, {"source": "clinicpro_context_clinicpro_backend", "target": "clinicpro_context_language", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CONTEXT.md", "source_location": "L6", "weight": 1.0}, {"source": "clinicpro_context_language", "target": "clinicpro_context_clinic_configuration", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CONTEXT.md", "source_location": "L8", "weight": 1.0}, {"source": "clinicpro_context_language", "target": "clinicpro_context_treatment", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CONTEXT.md", "source_location": "L21", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/3bdfa81cc0a4bec0643811f2330219d6a5d2e154a06d3bd9ad2aa546828eb19c.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/3bef39dcbe12e69cfadd5b1996d7042adcc7dacff8509cdb8259024c22aa6581.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/3e0c06ccca281c5b076a08f365cb7c31ebfd8f321a2871c59c170003fd6dc0e2.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/419f08e26fba11c4270d1cb66ad89a34e2a2af10ddf32e8379274d9315d381b7.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/4286ad4c2fe1aeb1844dd41b0746c8f8293252abdab003a7c7c1e1823f768bb9.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/43445dfea43882e0d01e82bdc2a27d3f48cbbd8281afb1dedea41f761c4a061e.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/46ef48d771de1bda3036463408989223e3bb3f5d9977f256051518ba7b842453.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/532f0fcbb18a234f1c7c32da700afb00dbf56209a1e69092049aa5d43d632447.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/53d246eeba97e4142c1aa77982f4767a200265283df2c248241052d68e261d7c.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/5e992df0892069586fe4c1f469ed7f81b088014923b72196590fa78e6390388b.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/61f4c7f58b85061746c135102be2d56a59137ecd28deda0c1f4eca408a0b65bf.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0005_treatment_workflows_are_tagged_services_md", "label": "0005-treatment-workflows-are-tagged-services.md", "file_type": "document", "source_file": "docs/adr/0005-treatment-workflows-are-tagged-services.md", "source_location": "L1"}, {"id": "adr_0005_treatment_workflows_are_tagged_services_treatment_workflows_are_tagged_services_not_a_configurable_engine", "label": "Treatment workflows are tagged services, not a configurable engine", "file_type": "document", "source_file": "docs/adr/0005-treatment-workflows-are-tagged-services.md", "source_location": "L1"}, {"id": "adr_0005_treatment_workflows_are_tagged_services_considered_options", "label": "Considered Options", "file_type": "document", "source_file": "docs/adr/0005-treatment-workflows-are-tagged-services.md", "source_location": "L9"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0005_treatment_workflows_are_tagged_services_md", "target": "adr_0005_treatment_workflows_are_tagged_services_treatment_workflows_are_tagged_services_not_a_configurable_engine", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0005-treatment-workflows-are-tagged-services.md", "source_location": "L1", "weight": 1.0}, {"source": "adr_0005_treatment_workflows_are_tagged_services_treatment_workflows_are_tagged_services_not_a_configurable_engine", "target": "adr_0005_treatment_workflows_are_tagged_services_considered_options", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0005-treatment-workflows-are-tagged-services.md", "source_location": "L9", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/6229d20d70b20bb4599f759d23807b3389d4fcd9678576397378f605e713d270.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/65cbc83a36d24af2358a0055c93c0cd85eccce0da2b5cc41123853e1307ecc39.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/6bc8654e16dbd218cf1eeb6d8dcfe880205c7b39491e020323b43182b1927fe3.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0004_session_parameters_are_json_keyed_by_resource_type_md", "label": "0004-session-parameters-are-json-keyed-by-resource-type.md", "file_type": "document", "source_file": "docs/adr/0004-session-parameters-are-json-keyed-by-resource-type.md", "source_location": "L1"}, {"id": "adr_0004_session_parameters_are_json_keyed_by_resource_type_session_parameters_are_json_described_by_the_resource_type", "label": "Session parameters are JSON, described by the resource type", "file_type": "document", "source_file": "docs/adr/0004-session-parameters-are-json-keyed-by-resource-type.md", "source_location": "L1"}, {"id": "adr_0004_session_parameters_are_json_keyed_by_resource_type_consequences", "label": "Consequences", "file_type": "document", "source_file": "docs/adr/0004-session-parameters-are-json-keyed-by-resource-type.md", "source_location": "L10"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0004_session_parameters_are_json_keyed_by_resource_type_md", "target": "adr_0004_session_parameters_are_json_keyed_by_resource_type_session_parameters_are_json_described_by_the_resource_type", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0004-session-parameters-are-json-keyed-by-resource-type.md", "source_location": "L1", "weight": 1.0}, {"source": "adr_0004_session_parameters_are_json_keyed_by_resource_type_session_parameters_are_json_described_by_the_resource_type", "target": "adr_0004_session_parameters_are_json_keyed_by_resource_type_consequences", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0004-session-parameters-are-json-keyed-by-resource-type.md", "source_location": "L10", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/6eff7a5ae4faa1a7abc126d126efc666b9e8e10ff293d484ccb0ec7ddebcdc8f.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/6f4f5ec7bdf3cc6591a29831bd9c3ef8eea85e5837c04b3e4911d94f6bc5fc8d.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/6fae579b98a64e5f987fc6c67a3fbfc2c7f5fabf96fc120b9161d394154583f9.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/700da6d0e219ac1e85e86b6720b4e90f01b84cf948453627d3050ee863f97d76.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/803cf63113dc5e82f6ddb30d7fb7adf964c6f45bf13ad773944c84f80f713efb.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082035_php", "label": "Version20260804082035.php", "file_type": "code", "source_file": "migrations/Version20260804082035.php", "source_location": "L1"}, {"id": "migrations_version20260804082035_version20260804082035", "label": "Version20260804082035", "file_type": "code", "source_file": "migrations/Version20260804082035.php", "source_location": "L17"}, {"id": "abstractmigration", "label": "AbstractMigration", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "migrations_version20260804082035_version20260804082035_getdescription", "label": ".getDescription()", "file_type": "code", "source_file": "migrations/Version20260804082035.php", "source_location": "L19"}, {"id": "migrations_version20260804082035_version20260804082035_up", "label": ".up()", "file_type": "code", "source_file": "migrations/Version20260804082035.php", "source_location": "L24"}, {"id": "schema", "label": "Schema", "file_type": "code", "source_file": "migrations/Version20260804082035.php", "source_location": "L24"}, {"id": "migrations_version20260804082035_version20260804082035_down", "label": ".down()", "file_type": "code", "source_file": "migrations/Version20260804082035.php", "source_location": "L43"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082035_php", "target": "schema", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L7", "weight": 1.0}, {"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082035_php", "target": "abstractmigration", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L8", "weight": 1.0}, {"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082035_php", "target": "migrations_version20260804082035_version20260804082035", "relation": "contains", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L17", "weight": 1.0}, {"source": "migrations_version20260804082035_version20260804082035", "target": "abstractmigration", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L17", "weight": 1.0}, {"source": "migrations_version20260804082035_version20260804082035", "target": "migrations_version20260804082035_version20260804082035_getdescription", "relation": "method", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L19", "weight": 1.0}, {"source": "migrations_version20260804082035_version20260804082035", "target": "migrations_version20260804082035_version20260804082035_up", "relation": "method", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L24", "weight": 1.0}, {"source": "migrations_version20260804082035_version20260804082035_up", "target": "schema", "relation": "references", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L24", "weight": 1.0, "context": "parameter_type"}, {"source": "migrations_version20260804082035_version20260804082035", "target": "migrations_version20260804082035_version20260804082035_down", "relation": "method", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L43", "weight": 1.0}, {"source": "migrations_version20260804082035_version20260804082035_down", "target": "schema", "relation": "references", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082035.php", "source_location": "L43", "weight": 1.0, "context": "parameter_type"}], "raw_calls": [{"caller_nid": "migrations_version20260804082035_version20260804082035_up", "callee": "addSql", "is_member_call": true, "source_file": "/Users/hamed/pj/my_pj/clinic_pro/clinicpro/migrations/Version20260804082035.php", "source_location": "L26", "receiver": null}, {"caller_nid": "migrations_version20260804082035_version20260804082035_down", "callee": "addSql", "is_member_call": true, "source_file": "/Users/hamed/pj/my_pj/clinic_pro/clinicpro/migrations/Version20260804082035.php", "source_location": "L45", "receiver": null}]}
|
||||||
graphify-out/cache/ast/v0.8.44/822735aad0a3d8ea927b5c50c65b907438424cd01701ea1905302918f615b5da.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/8601b5648a45bdd5135a49e0e74521a39528cfe4447594b572425b2e01997817.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_src_shared_constant_errorcodes_php", "label": "ErrorCodes.php", "file_type": "code", "source_file": "src/Shared/Constant/ErrorCodes.php", "source_location": "L1"}, {"id": "constant_errorcodes_errorcodes", "label": "ErrorCodes", "file_type": "code", "source_file": "src/Shared/Constant/ErrorCodes.php", "source_location": "L5"}, {"id": "constant_errorcodes_errorcodes_message", "label": ".message()", "file_type": "code", "source_file": "src/Shared/Constant/ErrorCodes.php", "source_location": "L136"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_src_shared_constant_errorcodes_php", "target": "constant_errorcodes_errorcodes", "relation": "contains", "confidence": "EXTRACTED", "source_file": "src/Shared/Constant/ErrorCodes.php", "source_location": "L5", "weight": 1.0}, {"source": "constant_errorcodes_errorcodes", "target": "constant_errorcodes_errorcodes_message", "relation": "method", "confidence": "EXTRACTED", "source_file": "src/Shared/Constant/ErrorCodes.php", "source_location": "L136", "weight": 1.0}], "raw_calls": []}
|
||||||
graphify-out/cache/ast/v0.8.44/882b8ccb807816d18368c4db63664d26f3e1e2fadbe38280935a250224102d2d.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/8bd30ded11b61493e69f2aadbabe5048e3b70f9325ee78b141f5fba300848d77.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/961e3ff480aa6c2c6ee75a4f1d4af642aa4984311671414e6af36b8982bd8b38.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/a051613355f86a776d0a1e44c959773785fe3cab375fb5c0437e1bd7a680d238.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/a3a35af84b0201b6af00659d9e1a29296b1fbb484e5f96932e1d9c97b7e1faf4.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/a5d6ff0a578c4815fee3fea7d40fac999556f4af33c55ad76721db72604057b4.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/a5fa078fe6602dcbae9d0a5bfcd460197a650d69361468ef273de4c1b3b7d8d4.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0002_treatment_areas_are_snapshotted_md", "label": "0002-treatment-areas-are-snapshotted.md", "file_type": "document", "source_file": "docs/adr/0002-treatment-areas-are-snapshotted.md", "source_location": "L1"}, {"id": "adr_0002_treatment_areas_are_snapshotted_a_treatment_case_snapshots_its_areas", "label": "A Treatment Case snapshots its areas", "file_type": "document", "source_file": "docs/adr/0002-treatment-areas-are-snapshotted.md", "source_location": "L1"}, {"id": "adr_0002_treatment_areas_are_snapshotted_consequences", "label": "Consequences", "file_type": "document", "source_file": "docs/adr/0002-treatment-areas-are-snapshotted.md", "source_location": "L8"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0002_treatment_areas_are_snapshotted_md", "target": "adr_0002_treatment_areas_are_snapshotted_a_treatment_case_snapshots_its_areas", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0002-treatment-areas-are-snapshotted.md", "source_location": "L1", "weight": 1.0}, {"source": "adr_0002_treatment_areas_are_snapshotted_a_treatment_case_snapshots_its_areas", "target": "adr_0002_treatment_areas_are_snapshotted_consequences", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0002-treatment-areas-are-snapshotted.md", "source_location": "L8", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/a831c4a57bebbd5d786265d9d33e3dc06affa056d087d047f6be5c3223ab2074.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/b2109f4d7f5208f8eecaea0d855612d00ecffcd6bc09da9cf3e07f2ab7da0a4a.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/b51569102387519b7b97e24f18dca6561a8a52a18840d7844ccda0fad1991205.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/bc68f7f551455645c2cc2b38b0362af99b11a003dee631de96736cc93903b06e.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082400_php", "label": "Version20260804082400.php", "file_type": "code", "source_file": "migrations/Version20260804082400.php", "source_location": "L1"}, {"id": "migrations_version20260804082400_version20260804082400", "label": "Version20260804082400", "file_type": "code", "source_file": "migrations/Version20260804082400.php", "source_location": "L17"}, {"id": "abstractmigration", "label": "AbstractMigration", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "migrations_version20260804082400_version20260804082400_getdescription", "label": ".getDescription()", "file_type": "code", "source_file": "migrations/Version20260804082400.php", "source_location": "L19"}, {"id": "migrations_version20260804082400_version20260804082400_up", "label": ".up()", "file_type": "code", "source_file": "migrations/Version20260804082400.php", "source_location": "L24"}, {"id": "schema", "label": "Schema", "file_type": "code", "source_file": "migrations/Version20260804082400.php", "source_location": "L24"}, {"id": "migrations_version20260804082400_version20260804082400_down", "label": ".down()", "file_type": "code", "source_file": "migrations/Version20260804082400.php", "source_location": "L29"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082400_php", "target": "schema", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L7", "weight": 1.0}, {"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082400_php", "target": "abstractmigration", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L8", "weight": 1.0}, {"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_migrations_version20260804082400_php", "target": "migrations_version20260804082400_version20260804082400", "relation": "contains", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L17", "weight": 1.0}, {"source": "migrations_version20260804082400_version20260804082400", "target": "abstractmigration", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L17", "weight": 1.0}, {"source": "migrations_version20260804082400_version20260804082400", "target": "migrations_version20260804082400_version20260804082400_getdescription", "relation": "method", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L19", "weight": 1.0}, {"source": "migrations_version20260804082400_version20260804082400", "target": "migrations_version20260804082400_version20260804082400_up", "relation": "method", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L24", "weight": 1.0}, {"source": "migrations_version20260804082400_version20260804082400_up", "target": "schema", "relation": "references", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L24", "weight": 1.0, "context": "parameter_type"}, {"source": "migrations_version20260804082400_version20260804082400", "target": "migrations_version20260804082400_version20260804082400_down", "relation": "method", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L29", "weight": 1.0}, {"source": "migrations_version20260804082400_version20260804082400_down", "target": "schema", "relation": "references", "confidence": "EXTRACTED", "source_file": "migrations/Version20260804082400.php", "source_location": "L29", "weight": 1.0, "context": "parameter_type"}], "raw_calls": [{"caller_nid": "migrations_version20260804082400_version20260804082400_up", "callee": "addSql", "is_member_call": true, "source_file": "/Users/hamed/pj/my_pj/clinic_pro/clinicpro/migrations/Version20260804082400.php", "source_location": "L26", "receiver": null}, {"caller_nid": "migrations_version20260804082400_version20260804082400_down", "callee": "addSql", "is_member_call": true, "source_file": "/Users/hamed/pj/my_pj/clinic_pro/clinicpro/migrations/Version20260804082400.php", "source_location": "L31", "receiver": null}]}
|
||||||
graphify-out/cache/ast/v0.8.44/c7deeb227b2874bba738abb420a6fecb923f7d03faaa7ae7b3fe6133c5c7199d.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/d665b34e87d79a777a6c9347a371c5c7038c93d6b9e2fcdba7247c8b1356a0c7.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/de18bf358b9bffd98359fa191158f6483281b02fd164ff6c148a7e3b81c30544.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/dfa42032860a462fecf10558c33bb5704950b3341d711de668a29413d0582193.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/e18d78ed4ed0f8d4aeabee313ff29852fd6bfcbb5884dfd8e64b38a85668c82f.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0006_clinical_record_is_separate_from_the_visit_record_md", "label": "0006-clinical-record-is-separate-from-the-visit-record.md", "file_type": "document", "source_file": "docs/adr/0006-clinical-record-is-separate-from-the-visit-record.md", "source_location": "L1"}, {"id": "adr_0006_clinical_record_is_separate_from_the_visit_record_the_clinical_record_of_a_session_is_separate_from_its_visit_record", "label": "The clinical record of a session is separate from its visit record", "file_type": "document", "source_file": "docs/adr/0006-clinical-record-is-separate-from-the-visit-record.md", "source_location": "L1"}, {"id": "adr_0006_clinical_record_is_separate_from_the_visit_record_consequences", "label": "Consequences", "file_type": "document", "source_file": "docs/adr/0006-clinical-record-is-separate-from-the-visit-record.md", "source_location": "L10"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0006_clinical_record_is_separate_from_the_visit_record_md", "target": "adr_0006_clinical_record_is_separate_from_the_visit_record_the_clinical_record_of_a_session_is_separate_from_its_visit_record", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0006-clinical-record-is-separate-from-the-visit-record.md", "source_location": "L1", "weight": 1.0}, {"source": "adr_0006_clinical_record_is_separate_from_the_visit_record_the_clinical_record_of_a_session_is_separate_from_its_visit_record", "target": "adr_0006_clinical_record_is_separate_from_the_visit_record_consequences", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0006-clinical-record-is-separate-from-the-visit-record.md", "source_location": "L10", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/e2984972bf7abf11ad01f22e847a7c32c4b5ebf3b7778d4348bc68b0ea0ce897.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/edc1fdefda62f3add53ef1dc1bdc0255a8ff4eb13215afe7d5ba0058dfad8c32.json
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_md", "label": "0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "file_type": "document", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L1"}, {"id": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_resource_backed_appointments_are_guarded_by_occupancy_not_the_doctor_slot_key", "label": "Resource-backed appointments are guarded by occupancy, not the doctor slot key", "file_type": "document", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L1"}, {"id": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_considered_options", "label": "Considered Options", "file_type": "document", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L10"}, {"id": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_consequences", "label": "Consequences", "file_type": "document", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L16"}], "edges": [{"source": "users_hamed_pj_my_pj_clinic_pro_clinicpro_docs_adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_md", "target": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_resource_backed_appointments_are_guarded_by_occupancy_not_the_doctor_slot_key", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L1", "weight": 1.0}, {"source": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_resource_backed_appointments_are_guarded_by_occupancy_not_the_doctor_slot_key", "target": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_considered_options", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L10", "weight": 1.0}, {"source": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_resource_backed_appointments_are_guarded_by_occupancy_not_the_doctor_slot_key", "target": "adr_0003_resource_backed_appointments_drop_the_doctor_slot_key_consequences", "relation": "contains", "confidence": "EXTRACTED", "source_file": "docs/adr/0003-resource-backed-appointments-drop-the-doctor-slot-key.md", "source_location": "L16", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}
|
||||||
graphify-out/cache/ast/v0.8.44/f587200f8179463f558961ac5b53be96fd2e0e8938491390ec024f220162b937.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/f5dd65b244278752a9a1f3bc98d25305b606546d570a0948e7f8768cccfc4e42.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/f7076795ce0cc660c7537ab63106d2f052cb4ade8b7df13cc0f44305ba2d0f66.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/ff3d832d5b25683f4f1de4a74f12f6535506d5e1680e3b271813e624be39b338.json
Vendored
+1
File diff suppressed because one or more lines are too long
graphify-out/cache/ast/v0.8.44/ffbffe5efc33664cc36ff6db6376941abe1b8ee47dcea18ffdaab08be14f2d84.json
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+13320
-2686
File diff suppressed because it is too large
Load Diff
+526
-336
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user