# کاربران تستی **پنل ادمین:** https://clinic-pro.ddev.site/admin > رمز عبور همهٔ پرسوناها: `QaTest@1234` این فایل وضعیت واقعی دیتابیس لوکال پس از بازسازی کامل (drop → migrate → seed) را توصیف می‌کند. صحتش با `node .claude/skills/qa-clinicpro/driver.mjs roles` قابل تأیید است — اگر ردیفی `✗` گرفت، این فایل کهنه شده است. --- ## پرسوناها واحد کار «پرسونا» است نه `ROLE_*`؛ پزشک مستقل و پزشک عضو کلینیک هر دو `ROLE_DOCTOR` دارند ولی دادهٔ متفاوتی می‌بینند. | پرسونا | موبایل | نقش‌ها | تمایز | |---|---|---|---| | `admin` | `09120671756` | `ROLE_ADMIN` | — | | `clinic` | `09127000000` | `ROLE_CLINIC` | مالک «کلینیک تست QA» | | `secretary` | `09123456778` | `ROLE_SECRETARY` | منشیِ `doctor_solo` | | `doctor` | `09390039833` | `ROLE_DOCTOR` | پزشک ساده، بدون کلینیک | | `representation` | `09124000001` | `ROLE_REPRESENTATION` | نمایندهٔ شهری | | `doctor_solo` | `09129000001` | `ROLE_DOCTOR` | مطب شخصی، بدون کلینیک | | `doctor_member` | `09129000002` | `ROLE_DOCTOR` | عضو «کلینیک تست QA» → موقع ورود «انتخاب محیط کاری» می‌بیند | | `clinic_doctor` | `09129000003` | `ROLE_CLINIC` + `ROLE_DOCTOR` | چندنقشی، مالک «کلینیک تست چندنقشی» | | `secretary_clinic` | `09129000004` | `ROLE_SECRETARY` | منشیِ `doctor_member` در کلینیک | | `unclaimed_doctor` | `09129000005` | `ROLE_UNCLAIMED_DOCTOR` | — | | `patient` | `09129000006` | `ROLE_USER` | کاربر عادی سایت | | `importer` | `09129000007` | `ROLE_IMPORTER` | — | `patient`، `unclaimed_doctor` و `importer` به پنل مدیریت دسترسی ندارند و در صفحهٔ ورود پیام «حساب شما دسترسی به پنل مدیریت را ندارد» می‌گیرند. این باگ نیست: `PasswordAuthenticator` هر کاربری را که `User::isStaff()` نباشد رد می‌کند. ## شناسه‌ها | موجودیت | نام | UUID | |---|---|---| | پزشک `doctor_solo` | سارا مستقل | `01e2a9b4-72f4-4a48-924c-0f95bb77a994` | | پزشک `doctor_member` | رضا عضوکلینیک | `439c9935-77bc-4f72-b73d-2432712bb6f5` | | پزشک `clinic_doctor` | نیما چندنقشی | `e3e4c2bf-170a-479c-a385-4af7d57fcbbe` | | پزشک `doctor` | کاوه قدیمی | `c3311b98-86b7-4d8e-8538-1390c36c2a90` | | پروفایل تصاحب‌نشده | تصاحب نشده تست | `ded7a65d-d0fa-47e0-bc16-e801c5c75147` | | کلینیک تست QA | — | `bcb00726-2343-4d63-90c6-d0175cc74591` | | کلینیک تست چندنقشی | — | `e62f69a2-381b-4a6c-9235-7f9c173f3c46` | هر سه پزشکِ `doctor_solo` / `doctor_member` / `clinic_doctor` آدرس مطب، تخصص و برنامهٔ هفتگی (شنبه تا چهارشنبه، ۰۹:۰۰–۱۳:۰۰ و ۱۶:۰۰–۱۹:۰۰، اسلات ۲۰ دقیقه‌ای) دارند، پس صفحات نوبت‌دهی‌شان خالی نیستند. ## دادهٔ انبوه `app:seed-demo-data` حدود ۸٬۴۰۰ کاربر، ۱۸۰ پزشک، ۲۰۰ کلینیک، ۲۵ نماینده و ۱۵٬۰۰۰ نوبت می‌سازد — برای تست «دادهٔ زیاد» نیازی به seed اضافه نیست. --- ## بازسازی از صفر ترتیب اجباری است — وابستگی‌ها چرخه‌ای‌اند: ```bash ddev exec php bin/console doctrine:schema:drop --full-database --force ddev exec php bin/console doctrine:migrations:migrate --no-interaction ddev exec php bin/console app:create-admin 09120671756 'QaTest@1234' # نماینده‌ها باید قبل از شهرها باشند: data/seed/cities.json به representation_id # های ۱ تا ۳ ارجاع می‌دهد و app:seed-categories اعتبارسنجی‌شان می‌کند. # POST /api/v1/representation ×۳ (با توکن ادمین) ddev exec php bin/console app:seed-categories --no-interaction ddev exec php bin/console app:seed-sms-message-templates --no-interaction ddev exec php bin/console app:seed-demo-data --purge --no-interaction ``` `app:seed-demo-data` خودش بازهٔ `09124000%` را مالک است و نماینده‌های مرحلهٔ قبل را purge و بازسازی می‌کند؛ بعد از آن `cities.representation_id` به شناسه‌های قدیمی اشاره می‌کند و باید به شناسه‌های جدید نگاشت شود. سپس پرسوناها از راه اندپوینت‌های خود اپ ساخته می‌شوند: `POST /api/v1/admin/doctors` · `POST /api/v1/admin/clinic` · `POST /api/v1/admin/clinic/{uuid}/invite-doctor` + `POST /api/v1/doctor/invitation/{uuid}/respond` · `POST /api/v1/secretary` · `POST /api/v1/admin/doctors/import` · `send-code → verify-code → register` برای `patient`. `ROLE_IMPORTER` و `ROLE_UNCLAIMED_DOCTOR` **هیچ مسیر اپلیکیشنی ندارند** — نگاشت نقش در `AdminApiController::updateUserRole` فقط `admin/doctor/secretary/clinic/patient` را می‌شناسد، پس این دو با SQL مستقیم ست می‌شوند. ## نکته‌ها - **کپچا:** نصب تازه `ALTCHA_ENABLED=true` دارد و override پنل خالی است، پس لاگین و ثبت‌نام اسکریپتی رد می‌شود. از پنل ادمین یا `PATCH /api/v1/admin/settings {"altcha_enabled":"0"}` غیرفعالش کن. - **کد OTP در dev همیشه `12345` است** (`OtpService::sendCode`). - **`send-code` سقف ۵ درخواست در ساعت به‌ازای هر IP دارد.** برای تست‌های انبوه توکن را مستقیم بساز: `ddev exec 'php bin/console lexik:jwt:generate-token --user-class="App\\Auth\\Entity\\User"'` - **رمز پس از ریست:** `ddev exec php bin/console security:hash-password 'QaTest@1234'` و هش را در `users.password_hash` بگذار. کاربرانی که از راه `POST /api/v1/admin/doctors` یا `/api/v1/admin/clinic` ساخته می‌شوند رمز نمی‌گیرند. ## نام پزشک بدون عنوان نام ذخیره‌شدهٔ پزشک **هرگز** پیشوند «دکتر» ندارد؛ همهٔ مسیرهای ثبت و ویرایش آن را با `PersianText::stripDoctorTitle()` حذف می‌کنند. افزودن عنوان کار لایهٔ نمایش است — `nobat724_front` برای عنوان صفحه و JSON-LD از `doctorTitle()` استفاده می‌کند (idempotent)، و پنل ادمین اصلاً عنوان اضافه نمی‌کند. پاک‌سازی دادهٔ قدیمی: `php bin/console app:doctors:fix-irimc-names --all --dry-run`