# کاربران تستی **پنل ادمین:** https://clinic-pro.ddev.site/admin — **سایت عمومی:** `yasuj-nobat.localhost:3000` > رمز عبور همهٔ حساب‌های کارکنان: `QaTest@1234` · کد OTP در dev همیشه `12345` کل این محیط با **یک دستور** ساخته می‌شود: ```bash ddev exec php bin/console app:seed-scenarios --reset -n ``` `--reset` دیتابیس را کامل خالی می‌کند، migrationها را از صفر می‌زند، دادهٔ پایه (نماینده‌ها → دسته‌بندی‌ها → کاتالوگ بیمه → خاموش‌کردن کپچا) را می‌سازد و بعد سه سناریو را می‌چیند. بدون `--reset` فقط سناریوها ساخته می‌شوند و روی دیتابیسی که قبلاً seed شده با خطا برمی‌گردد. > **UUIDها با هر اجرا عوض می‌شوند.** جدول‌های زیر شکل داده را نشان می‌دهند نه شناسه‌های > ثابت؛ برای گرفتن uuidهای فعلی از خود API یا دیتابیس بپرسید. --- ## سناریوی ۱ — پزشک مستقل، نوبت‌دهی سرویسی | نقش | موبایل | توضیح | |---|---|---| | پزشک | `0912000101` | سارا مرادی — مطب شخصی، بدون کلینیک | | منشی | `0912000109` | منشیِ همان پزشک | | بیماران | `09120001100` … `09120001104` | ۵ بیمار با پرونده | - **حالت نوبت‌دهی:** `service` · بافر ۱۰ دقیقه · شنبه تا چهارشنبه ۰۹:۰۰–۱۷:۰۰ - **سرویس‌ها:** مشاوره پوست (۲۰د) · لیزر صورت (۳۰د، additional ۲۰) · تزریق ژل (۴۵د) · میکرونیدلینگ (۶۰د، additional ۴۰) - **بیمه:** تامین اجتماعی، بیمه ایران - **نوبت‌ها:** ۹ نوبت در ۵ وضعیت (انجام‌شده، لغو کاربر، عدم حضور، تأییدشده، در انتظار پرداخت) که دو تای آن‌ها **امروز** است ## سناریوی ۲ — پزشکی که مالک کلینیک است | نقش | موبایل | توضیح | |---|---|---| | پزشک + مالک کلینیک | `0912000201` | امیر کاظمی — مالک «کلینیک تخصصی مهر»، خودش هم در کلینیک نوبت می‌دهد | | پزشک عضو (سرویسی) | `0912000202` | نگار سلطانی | | پزشک عضو (اسلاتی) | `0912000203` | بهرام فتحی | | پزشک عضو (اسلاتی) | `0912000204` | الهام قاسمی | | منشی | `0912000209` | روی هر ۴ پزشک | | بیماران | `09120001200` … `09120001207` | ۸ بیمار | - **ترکیب حالت‌ها:** ۲ سرویسی + ۲ اسلاتی، همه شنبه تا چهارشنبه ۱۶:۰۰–۲۱:۰۰ - **دستگاه‌ها:** ۲ لیزر (الکساندرایت، دایود) با setup/cleanup و تقویم کاری + ۲ اتاق درمان - **سرویس‌ها:** لیزر کامل بدن (۹۰د) · لیزر زیربغل (۲۰د) · ویزیت پوست (۱۵د) · هیدرودرم (۴۵د) - **وابستگی به دستگاه:** دو سرویس لیزری هرکدام یک بخش (`SegmentTemplate`) با نیازمندی انحصاری روی نوع منبع «دستگاه لیزر» دارند - **بیمه:** تامین اجتماعی، سلامت ایرانیان، بیمه آسیا این حساب **دو محیط کاری** دارد (مطب شخصی + کلینیک). سرویس‌ها و دستگاه‌ها زیر محیط *کلینیک* اند، پس تا وقتی محیط عوض نشود لیستشان خالی است — این درست است، نه باگ: ```bash POST /api/v1/auth/switch-context {"db_uuid": ""} ``` ## سناریوی ۳ — کلینیک مستقل با مالکِ غیرپزشک | نقش | موبایل | توضیح | |---|---|---| | مالک کلینیک | `0912000301` | رضا شریفی — **پزشک نیست**، فقط `ROLE_CLINIC` | | پزشک (اسلاتی) | `0912000302` | پیمان اکبری | | پزشک (سرویسی) | `0912000303` | مینا یوسفی | | پزشک (منبع‌محور) | `0912000304` | آرش نوری | | منشی | `0912000309` | روی هر ۳ پزشک | | بیماران | `09120001300` … `09120001307` | ۸ بیمار | - **هر سه حالت نوبت‌دهی** اینجا زنده‌اند: `slot`، `service` و `resource` - **ساعت کاری:** شنبه تا پنجشنبه ۰۸:۰۰–۱۴:۰۰ - **دستگاه‌ها:** ۳ لیزر (CO2 فرکشنال، NdYAG، دایود) + دستگاه RF + دستگاه کرایو - **سرویس‌ها:** ویزیت عمومی (۱۵د) · لیزر CO2 (۴۰د) · کرایوتراپی (۲۵د) · RF فرکشنال (۵۰د) - **بیمه:** تامین اجتماعی، سلامت ایرانیان، بیمه دی مالکِ غیرپزشک عمدی است: هر مسیری که فرض کند مالکِ کلینیک یک `Doctor` دارد، باید همین‌جا بشکند نه در محیط واقعی. --- ## موتور نوبت‌دهی جدید (تسک‌های `docs/new_feture`) هر سه محیط، علاوه بر داده‌های بالا، دادهٔ زندهٔ موتور جدید هم دارند: | تسک | چه چیزی seed می‌شود | کجا دیده می‌شود | |---|---|---| | ۰۱ شعبه و اتاق | `DoctorAddress` به‌عنوان شعبه + منبع اتاق با تقویم | `GET /api/v1/resources` | | ۰۲ مدل منبع | نوع منبع، دستگاه، **مهارت** (`کار با لیزر`) با سطح، **استخر منبع** با اولویت | `GET /api/v1/resources` · `/skills` | | ۰۳ تقویم منبع | تقویم هفتگی هر دستگاه + یک **استثنای تعمیرات** هفتهٔ بعد | جستجوی آزاد آن بازه را رد می‌کند | | ۰۴ کاتالوگ نسل دوم | دستهٔ درختی، **گروه انتخاب** با بازهٔ ۱ تا ۲، **ناسازگاری** دو سرویس، **override شعبه**، مدت solo/additional | `GET /api/v1/service-items` | | ۰۵ برنامهٔ چندبخشی | سرویس اصلی هر محیط سه بخش دارد: بی‌حسی ۵د (اتاق انحصاری) → انتظار ۳۰د (اتاق **passive**) → لیزر ۲۰د (اتاق + دستگاه) | `GET /api/v1/service-item/{uuid}/segments` | | ۰۶ موتور دسترس‌پذیری | همان برنامه با منابع واقعی جستجو می‌شود | `POST /api/v1/appointment-availability` | | ۰۷ نگه‌داشتن و ثبت | **۲ نوبت در هر محیط از مسیر واقعی** hold → confirm، با بخش و اشغال منبع | `GET /api/v1/appointment/{uuid}/segments` | | **منبع↔سرویس** | رابطهٔ چند‌به‌چند با مدت و قیمت اختصاصی: دو دستگاه یک سرویس را با اعداد متفاوت می‌دهند | `GET /api/v1/resource/{uuid}/services` | | **دستهٔ مشترک** | دسته روی سرویس و منبع؛ یال «شامل بودن» بین دسته‌ها | مودال «سرویس‌ها» در صفحهٔ منابع | | ۰۸ عکس قیمت | لیست قیمت فعال + `PriceSnapshot` روی نوبت‌های واقعی با بیعانه | `GET /api/v1/price-lists` | > **تسک‌های ۹ تا ۱۴ (سیاست، پکیج، دوره، لغو/انتظار، رویداد و گزارش) به تصمیم مالک محصول > از محصول حذف شده‌اند.** مدل فعلی فقط منبع، سرویس و گزینه است — > [`docs/architecture/resource-first-model.md`](docs/architecture/resource-first-model.md). نوبت‌های موتور جدید **از `new Appointment(...)` ساخته نمی‌شوند**؛ از `AppointmentPlanBuilder` → `AvailabilityEngine` → `HoldService` → `BookingService` رد می‌شوند. برای همین اشغال منبع واقعی است و تقویم دستگاه واقعاً پر است — نه ردیف‌هایی که با INSERT ساخته شده‌اند و هیچ‌وقت از موتور رد نشده‌اند. ## چه چیزی با این داده قابل تست است | قابلیت | کجا | |---|---| | نوبت‌دهی اسلاتی | `0912000203` · `0912000204` · `0912000302` | | نوبت‌دهی سرویسی | `0912000101` · `0912000201` · `0912000202` · `0912000303` | | نوبت‌دهی منبع‌محور | `0912000304` (با تخصیص واقعی دستگاه) | | مطب شخصی در برابر کلینیک | سناریوی ۲ (یک کاربر، دو محیط) | | مالک پزشک در برابر مالک اداری | سناریوی ۲ در برابر سناریوی ۳ | | دستگاه و وابستگی سرویس به دستگاه | سناریوی ۲ و ۳ | | بیمه (پایه و تکمیلی، فرانشیز، سقف) | هر سه محیط | | پرداخت | ۳۲ پرداخت موفق روی نوبت‌های پرداخت‌شده | | پرونده بیمار | ۲۱ پرونده با کد ملی روی پروفایل | ## نکته‌ها - **کپچا:** روی دیتابیس تازه پیش‌فرضش **روشن** است و هیچ‌کس نمی‌تواند وارد شود. سیدر ردیف `site_config.altcha_enabled = '0'` را می‌گذارد تا محیط قابل ورود بماند. - **لاگین با رمز فقط برای کارکنان است.** فیلد درخواست `mobile_number` است نه `mobile`: `POST /api/v1/user/login {"mobile_number": "...", "password": "..."}`. بیماران (`ROLE_USER`) عمداً فقط با OTP وارد می‌شوند (`send-code` → `verify-code` با `12345` → `otp-login`). - **`send-code` سقف ۵ درخواست در ساعت به‌ازای هر IP دارد.** - **نام پزشک بدون عنوان ذخیره می‌شود** — «دکتر» را لایهٔ نمایش اضافه می‌کند (`PersianText::stripDoctorTitle`). - **دادهٔ انبوه** جداست: `app:seed-demo-data` حدود ۵۰۰ پزشک و ۲۰هزار نوبت با INSERT خام می‌سازد و برای تست کارایی و ماژول نمایندگان است، نه برای تست سناریویی.