Files
clinicpro/TEST_USERS.md
T
hamedandClaude Opus 5 369f3ae710 feat(seed): one command that builds three complete, working environments
Manual testing had no environment to test in: the demo seeder builds volume
(500 doctors, 20k appointments via raw INSERT) for the representation module,
which is the wrong shape for walking through a scenario end to end.

app:seed-scenarios builds three environments that each work from login to
booking:

  1. an independent doctor, service mode, with services, schedule, insurance,
     patients and appointments
  2. a doctor who also owns a clinic, with three more doctors inside it, a
     slot/service mix, two laser devices and two rooms, and laser services that
     genuinely require a laser
  3. a clinic whose owner is not a doctor, with all three booking modes live
     (slot, service and resource), five devices, and the same full data set

Everything goes through entities and the real services rather than raw SQL, so
tenant pairs, the unique active-slot key and the insurance rules hold. The
status machine is walked step by step (completed only via confirmed) instead of
writing a status the application could never produce.

--reset drops the schema, re-runs migrations and seeds base data in one go.
Three things it has to handle, each found by it breaking:

- representations must exist before cities, because cities.json references them
  by id and the category importer validates that
- migrations run mid-process invalidate the EntityManager's connection, so the
  manager is taken from the registry and reset afterwards
- a sub-command's --no-interaction in ArrayInput is not enough; without
  setInteractive(false) the migration waits forever for a confirmation

It also writes site_config.altcha_enabled = '0'. On a freshly migrated database
the captcha defaults to on and nobody can log in at all — panel or site.

Verified against the running app, not just the database: booking-locations
reports the right mode per doctor, service slots respect the buffer, the
slot-mode doctor returns a session with 15 slots, the resource-mode doctor
returns 40 options each with a real device assignment, a patient booked a
service appointment through the public endpoint, and the admin panel renders
the seeded day for both clinic owners.

TEST_USERS.md is rewritten: every account it described was gone after the wipe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 18:41:03 +03:30

7.1 KiB
Raw Blame History

کاربران تستی

پنل ادمین: https://clinic-pro.ddev.site/adminسایت عمومی: yasuj-nobat.localhost:3000

رمز عبور همهٔ حساب‌های کارکنان: QaTest@1234 · کد OTP در dev همیشه 12345

کل این محیط با یک دستور ساخته می‌شود:

ddev exec php bin/console app:seed-scenarios --reset -n

--reset دیتابیس را کامل خالی می‌کند، migrationها را از صفر می‌زند، دادهٔ پایه (نماینده‌ها → دسته‌بندی‌ها → کاتالوگ بیمه → خاموش‌کردن کپچا) را می‌سازد و بعد سه سناریو را می‌چیند. بدون --reset فقط سناریوها ساخته می‌شوند و روی دیتابیسی که قبلاً seed شده با خطا برمی‌گردد.

UUIDها با هر اجرا عوض می‌شوند. جدول‌های زیر شکل داده را نشان می‌دهند نه شناسه‌های ثابت؛ برای گرفتن uuidهای فعلی از خود API یا دیتابیس بپرسید.


سناریوی ۱ — پزشک مستقل، نوبت‌دهی سرویسی

نقش موبایل توضیح
پزشک 0912000101 سارا مرادی — مطب شخصی، بدون کلینیک
منشی 0912000109 منشیِ همان پزشک
بیماران 0912000110009120001104 ۵ بیمار با پرونده
  • حالت نوبت‌دهی: service · بافر ۱۰ دقیقه · شنبه تا چهارشنبه ۰۹:۰۰–۱۷:۰۰
  • سرویس‌ها: مشاوره پوست (۲۰د) · لیزر صورت (۳۰د، additional ۲۰) · تزریق ژل (۴۵د) · میکرونیدلینگ (۶۰د، additional ۴۰)
  • بیمه: تامین اجتماعی، بیمه ایران
  • نوبت‌ها: ۹ نوبت در ۵ وضعیت (انجام‌شده، لغو کاربر، عدم حضور، تأییدشده، در انتظار پرداخت) که دو تای آن‌ها امروز است

سناریوی ۲ — پزشکی که مالک کلینیک است

نقش موبایل توضیح
پزشک + مالک کلینیک 0912000201 امیر کاظمی — مالک «کلینیک تخصصی مهر»، خودش هم در کلینیک نوبت می‌دهد
پزشک عضو (سرویسی) 0912000202 نگار سلطانی
پزشک عضو (اسلاتی) 0912000203 بهرام فتحی
پزشک عضو (اسلاتی) 0912000204 الهام قاسمی
منشی 0912000209 روی هر ۴ پزشک
بیماران 0912000120009120001207 ۸ بیمار
  • ترکیب حالت‌ها: ۲ سرویسی + ۲ اسلاتی، همه شنبه تا چهارشنبه ۱۶:۰۰–۲۱:۰۰
  • دستگاه‌ها: ۲ لیزر (الکساندرایت، دایود) با setup/cleanup و تقویم کاری + ۲ اتاق درمان
  • سرویس‌ها: لیزر کامل بدن (۹۰د) · لیزر زیربغل (۲۰د) · ویزیت پوست (۱۵د) · هیدرودرم (۴۵د)
  • وابستگی به دستگاه: دو سرویس لیزری هرکدام یک بخش (SegmentTemplate) با نیازمندی انحصاری روی نوع منبع «دستگاه لیزر» دارند
  • بیمه: تامین اجتماعی، سلامت ایرانیان، بیمه آسیا

این حساب دو محیط کاری دارد (مطب شخصی + کلینیک). سرویس‌ها و دستگاه‌ها زیر محیط کلینیک اند، پس تا وقتی محیط عوض نشود لیستشان خالی است — این درست است، نه باگ:

POST /api/v1/auth/switch-context  {"db_uuid": "<clinic_uuid>"}

سناریوی ۳ — کلینیک مستقل با مالکِ غیرپزشک

نقش موبایل توضیح
مالک کلینیک 0912000301 رضا شریفی — پزشک نیست، فقط ROLE_CLINIC
پزشک (اسلاتی) 0912000302 پیمان اکبری
پزشک (سرویسی) 0912000303 مینا یوسفی
پزشک (منبع‌محور) 0912000304 آرش نوری
منشی 0912000309 روی هر ۳ پزشک
بیماران 0912000130009120001307 ۸ بیمار
  • هر سه حالت نوبت‌دهی اینجا زنده‌اند: slot، service و resource
  • ساعت کاری: شنبه تا پنجشنبه ۰۸:۰۰–۱۴:۰۰
  • دستگاه‌ها: ۳ لیزر (CO2 فرکشنال، NdYAG، دایود) + دستگاه RF + دستگاه کرایو
  • سرویس‌ها: ویزیت عمومی (۱۵د) · لیزر CO2 (۴۰د) · کرایوتراپی (۲۵د) · RF فرکشنال (۵۰د)
  • بیمه: تامین اجتماعی، سلامت ایرانیان، بیمه دی

مالکِ غیرپزشک عمدی است: هر مسیری که فرض کند مالکِ کلینیک یک Doctor دارد، باید همین‌جا بشکند نه در محیط واقعی.


چه چیزی با این داده قابل تست است

قابلیت کجا
نوبت‌دهی اسلاتی 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-codeverify-code با 12345otp-login).
  • send-code سقف ۵ درخواست در ساعت به‌ازای هر IP دارد.
  • نام پزشک بدون عنوان ذخیره می‌شود — «دکتر» را لایهٔ نمایش اضافه می‌کند (PersianText::stripDoctorTitle).
  • دادهٔ انبوه جداست: app:seed-demo-data حدود ۵۰۰ پزشک و ۲۰هزار نوبت با INSERT خام می‌سازد و برای تست کارایی و ماژول نمایندگان است، نه برای تست سناریویی.