feat: update user roles and passwords in QA driver, enhance documentation with error codes, and improve trial activation error handling

This commit is contained in:
hamed
2026-07-19 15:19:03 +03:30
parent 3e841b5e57
commit 7761c37a3e
10 changed files with 326 additions and 109 deletions
+84 -92
View File
@@ -2,108 +2,100 @@
**پنل ادمین:** https://clinic-pro.ddev.site/admin
> رمز عبور همه کاربران seed‌شده: `Test@1234`
> رمز عبور همهٔ پرسوناها: `QaTest@1234`
این فایل وضعیت واقعی دیتابیس لوکال پس از بازسازی کامل (drop → migrate → seed) را
توصیف می‌کند. صحتش با `node .claude/skills/qa-clinicpro/driver.mjs roles` قابل
تأیید است — اگر ردیفی `✗` گرفت، این فایل کهنه شده است.
---
## ادمین
## پرسوناها
| فیلد | مقدار |
| ------ | --------------- |
| موبایل | `09100000001` |
| پسورد | `Test@1234` |
| نقش | `ROLE_ADMIN` |
| نام | مدیر سیستم |
واحد کار «پرسونا» است نه `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 اضافه نیست.
---
## کلینیک نمونه — تبریز
## بازسازی از صفر
| فیلد | مقدار |
| ----------- | -------------------------------------- |
| موبایل | `09100100000` |
| پسورد | `Test@1234` |
| نقش | `ROLE_CLINIC` |
| نام | کلینیک تخصصی امید تبریز |
| UUID کلینیک | `9ac73318-d313-4772-bf1e-418d47f8f4bc` |
| شهر | تبریز (id: 101) |
---
## دکتر نمونه کامل — تبریز
| فیلد | مقدار |
| ----------- | -------------------------------------- |
| موبایل | `09100100001` |
| پسورد | `Test@1234` |
| نقش | `ROLE_DOCTOR` |
| نام | دکتر آرمان رضایی |
| تخصص | قلب و عروق + داخلی |
| UUID دکتر | `2a3a7ab9-8d34-4118-862f-b458bcd6d77f` |
| کلینیک | کلینیک تخصصی امید تبریز (عضو) |
| آدرس مطب | تبریز، خیابان آزادی |
| برنامه کاری | شنبه–چهارشنبه ۹–۱۳ و ۱۴–۱۸، پنجشنبه ۹–۱۳ |
| بیمه | تأمین اجتماعی، خدمات درمانی، نیروهای مسلح، ایران |
---
## منشی دکتر نمونه
| فیلد | مقدار |
| ------ | ------------------- |
| موبایل | `09100100002` |
| پسورد | `Test@1234` |
| نقش | `ROLE_SECRETARY` |
| نام | خانم نرگس صادقی |
| مرتبط | دکتر آرمان رضایی |
---
## دکتران bulk (۱۵۰۰ دکتر در ۱۵ شهر)
هر شهر ۱۰۰ دکتر با توزیع واقعی تخصص:
| شهر | شروع موبایل | تعداد |
| ---------- | ------------- | ----- |
| تبریز | `09100100003` | ۱۰۰ |
| ارومیه | `09100100103` | ۱۰۰ |
| اردبیل | `09100100203` | ۱۰۰ |
| اصفهان | `09100100303` | ۱۰۰ |
| کرج | `09100100403` | ۱۰۰ |
| تهران | `09100100503` | ۱۰۰ |
| مشهد | `09100100603` | ۱۰۰ |
| اهواز | `09100100703` | ۱۰۰ |
| شیراز | `09100100803` | ۱۰۰ |
| کرمان | `09100100903` | ۱۰۰ |
| کرمانشاه | `09100101003` | ۱۰۰ |
| رشت | `09100101103` | ۱۰۰ |
| ساری | `09100101203` | ۱۰۰ |
| همدان | `09100101303` | ۱۰۰ |
| یزد | `09100101403` | ۱۰۰ |
توزیع تخصص در هر شهر:
- ۱۵ پزشک عمومی
- ۱۰ داخلی + قلب
- ۸ جراحی عمومی
- ۸ زنان و زایمان
- ۸ اطفال
- ۷ ارتوپدی
- ۶ گوارش، نورولوژی، پوست، چشم‌پزشکی، دندانپزشکی (هر کدام ۶)
- ۵ ENT، روانپزشکی (هر کدام ۵)
- ۴ اورولوژی
---
## ساخت مجدد
اگر دیتابیس ریست شد، ادمین را مستقیم در دیتابیس بساز:
ترتیب اجباری است — وابستگی‌ها چرخه‌ای‌اند:
```bash
ddev mysql -e "INSERT INTO users (uuid, mobile_number, password_hash, real_name, roles, status, created_at, updated_at) VALUES (UUID(), '09100000001', '\$2y\$13\$8.5nFvKRxQGAXfJMXPB6sO.eR.c1RNxj0nJalcQfhzFTiEXnfaJbG', 'مدیر سیستم', '[\"ROLE_USER\",\"ROLE_ADMIN\"]', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());"
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
```
برای seed دیتای واقعی دکتران و کلینیک:
`app:seed-demo-data` خودش بازهٔ `09124000%` را مالک است و نماینده‌های مرحلهٔ قبل را
purge و بازسازی می‌کند؛ بعد از آن `cities.representation_id` به شناسه‌های قدیمی اشاره
می‌کند و باید به شناسه‌های جدید نگاشت شود.
```bash
ddev exec php seed_realistic_data.php
```
سپس پرسوناها از راه اندپوینت‌های خود اپ ساخته می‌شوند:
`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 <mobile> --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` ساخته می‌شوند رمز نمی‌گیرند.