feat: enhance QA driver with detailed persona definitions for improved testing accuracy
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: qa-clinicpro
|
name: qa-clinicpro
|
||||||
description: تست QA اپلیکیشن ClinicPro مثل یک کاربر واقعی — اجرای اپ، ورود با هر نقش، پیمایش صفحات پنل ادمین، اسکرینشات، کشف خطاهای کنسول و شبکه، تست UI/UX و RTL، تست دسترسی نقشها (authz)، تست قرارداد API و اندازهگیری کارایی، و تولید Bug Report. Use when asked to QA, test, smoke-test, find bugs in, screenshot, or verify ClinicPro's admin panel or API — «تست کن»، «باگ پیدا کن»، «QA کن»، «این صفحه را بررسی کن».
|
description: تست QA اپلیکیشن ClinicPro مثل یک کاربر واقعی — ابتدا ساخت همهٔ نقشها و پروفایلهای کامل (پزشک مستقل، پزشک عضو کلینیک، کلینیک، منشی، نماینده، بیمار، …) و تعیین ماتریس سطح دسترسی، سپس تست ماتریس دسترسی با تکتک آنها. هر مانعی سر راه تست را مثل یک دولوپر ارشد Symfony/React خودش رفع میکند و تست را ادامه میدهد. اجرای اپ، ورود با هر نقش، پیمایش صفحات پنل ادمین، اسکرینشات، کشف خطاهای کنسول و شبکه، تست UI/UX و RTL، تست دسترسی نقشها (authz)، تست قرارداد API و اندازهگیری کارایی، و تولید Bug Report. Use when asked to QA, test, smoke-test, find bugs in, screenshot, or verify ClinicPro's admin panel or API — «تست کن»، «باگ پیدا کن»، «QA کن»، «این صفحه را بررسی کن».
|
||||||
---
|
---
|
||||||
|
|
||||||
# QA ClinicPro
|
# QA ClinicPro
|
||||||
@@ -33,17 +33,29 @@ ls "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|||||||
در دیتابیس وجود ندارند و همه `ERR_AUTH_005` میگیرند. اسکریپتهای `create_test_users.php`
|
در دیتابیس وجود ندارند و همه `ERR_AUTH_005` میگیرند. اسکریپتهای `create_test_users.php`
|
||||||
و `seed_realistic_data.php` هم که آن فایل ارجاع میدهد در ریپو نیستند.
|
و `seed_realistic_data.php` هم که آن فایل ارجاع میدهد در ریپو نیستند.
|
||||||
|
|
||||||
نقشهای واقعیِ کارکننده در `ROLES` داخل درایور هاردکد شدهاند:
|
پرسوناهای QA در `ROLES` داخل درایور تعریف شدهاند. **واحد کار «پرسونا» است، نه
|
||||||
|
`ROLE_*`** — پزشک مستقل و پزشک عضو کلینیک هر دو `ROLE_DOCTOR` دارند ولی دادهٔ متفاوتی
|
||||||
|
میبینند، پس هرکدام یک ردیف جداگانهاند.
|
||||||
|
|
||||||
| نقش | موبایل | پسورد |
|
| پرسونا | موبایل | پسورد | نقشها | تمایز |
|
||||||
|---|---|---|
|
|---|---|---|---|---|
|
||||||
| `admin` | `09120671756` | `QaTest@1234` |
|
| `admin` | `09120671756` | `QaTest@1234` | `ROLE_ADMIN` | — |
|
||||||
| `clinic` | `09127000000` | `QaTest@1234` |
|
| `clinic` | `09127000000` | `QaTest@1234` | `ROLE_CLINIC` | مالک کلینیک |
|
||||||
| `secretary` | `09123456778` | `QaTest@1234` |
|
| `secretary` | `09123456778` | `QaTest@1234` | `ROLE_SECRETARY` | منشیِ یک پزشک |
|
||||||
| `doctor` | `09390039833` | `09390039833` |
|
| `doctor` | `09390039833` | `09390039833` | `ROLE_DOCTOR` | حساب قدیمی، وضعیت عضویتش نامعلوم |
|
||||||
| `representation` | `09124000001` | `09124000001` |
|
| `representation` | `09124000001` | `09124000001` | `ROLE_REPRESENTATION` | نماینده شهر |
|
||||||
|
| `doctor_solo` | `09129000001` | `QaTest@1234` | `ROLE_DOCTOR` | **پزشک مستقل** — مطب شخصی، بدون کلینیک |
|
||||||
|
| `doctor_member` | `09129000002` | `QaTest@1234` | `ROLE_DOCTOR` | پزشک **عضو کلینیک** |
|
||||||
|
| `clinic_doctor` | `09129000003` | `QaTest@1234` | `ROLE_CLINIC`+`ROLE_DOCTOR` | چندنقشی |
|
||||||
|
| `secretary_clinic` | `09129000004` | `QaTest@1234` | `ROLE_SECRETARY` | منشیِ کلینیک (نه پزشک) |
|
||||||
|
| `unclaimed_doctor` | `09129000005` | `QaTest@1234` | `ROLE_UNCLAIMED_DOCTOR` | پروفایل ایمپورتشدهٔ تصاحبنشده |
|
||||||
|
| `patient` | `09129000006` | `QaTest@1234` | `ROLE_USER` | کاربر عادی سایت |
|
||||||
|
| `importer` | `09129000007` | `QaTest@1234` | `ROLE_IMPORTER` | — |
|
||||||
|
|
||||||
سه تای اول پسوردشان عمداً برای QA ست شده. اگر DB ریست شد، دوباره ست کن:
|
پنج ردیف اول موجودند. **هفت ردیف آخر تا وقتی Phase 0 اجرا نشده وجود ندارند** و
|
||||||
|
`driver.mjs roles` برایشان `✗` میدهد — این دقیقاً چک آمادگی است.
|
||||||
|
|
||||||
|
اگر DB ریست شد، پسورد پنجتای اول را دوباره ست کن:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ddev exec php bin/console security:hash-password 'QaTest@1234'
|
ddev exec php bin/console security:hash-password 'QaTest@1234'
|
||||||
@@ -74,6 +86,82 @@ representation 09124000001 ROLE_USER,ROLE_REPRESENTATION token 15min
|
|||||||
|
|
||||||
## مسیر اجرا (agent path)
|
## مسیر اجرا (agent path)
|
||||||
|
|
||||||
|
### ۰. Phase 0 — ساخت نقشها، پروفایلها و ماتریس دسترسی (اجباری، قبل از هر تست)
|
||||||
|
|
||||||
|
هیچ تستی را قبل از تمامشدن این فاز شروع نکن. خروجی این فاز سه چیز است:
|
||||||
|
**همهٔ پرسوناها موجود** · **پروفایل هرکدام کامل** · **ماتریس دسترسی مکتوب**.
|
||||||
|
|
||||||
|
**۰.۱ — کشف نقشها.** لیست بالا را دوباره از روی کد بساز، به آن استناد نکن؛ ممکن است
|
||||||
|
نقشی اضافه شده باشد:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rhoE "ROLE_[A-Z_]+" src/ assets/admin/ config/ | sort -u
|
||||||
|
ddev mysql -e "SELECT roles, COUNT(*) c FROM users GROUP BY roles ORDER BY c DESC;"
|
||||||
|
grep -n "role_hierarchy" -A 10 config/packages/security.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
هر نقشی که در کد هست و در جدول پرسوناها نیست را به `ROLES` در `driver.mjs` اضافه کن.
|
||||||
|
|
||||||
|
**۰.۲ — چک آمادگی.** ببین کدام پرسونا هنوز نیست:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node .claude/skills/qa-clinicpro/driver.mjs roles
|
||||||
|
```
|
||||||
|
|
||||||
|
**۰.۳ — ساخت پرسوناهای ناموجود.** برای هرکدام، **اول مسیر واقعی ساخت را در خود اپ پیدا
|
||||||
|
کن** و از همان استفاده کن — دستکاری مستقیم SQL پروفایل ناقص میسازد و تست را دروغین
|
||||||
|
میکند. به این ترتیب بگرد:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls src/*/Command/ # آیا کامند کنسولی برای ساخت کاربر هست؟
|
||||||
|
grep -rn "IsGranted" src/Admin/Controller/ # اندپوینتهای ادمینِ ساخت کاربر
|
||||||
|
sed -n '1,80p' docs/api/admin.md
|
||||||
|
```
|
||||||
|
|
||||||
|
فقط برای چیزی که هیچ مسیر اپلیکیشنی ندارد (مثلاً ستکردن `ROLE_IMPORTER` یا ساختن
|
||||||
|
`ROLE_UNCLAIMED_DOCTOR`) به `ddev mysql` برگرد، و در گزارش بنویس که کدام پرسونا
|
||||||
|
دستی ساخته شد.
|
||||||
|
|
||||||
|
**ترتیب ساخت مهم است** — وابستگی دارند:
|
||||||
|
|
||||||
|
```
|
||||||
|
کلینیک → doctor_member (عضو همان کلینیک) → secretary_clinic (منشیِ همان کلینیک)
|
||||||
|
پزشک → secretary (منشیِ همان پزشک)
|
||||||
|
```
|
||||||
|
|
||||||
|
**۰.۴ — کاملکردن پروفایل.** یک حسابِ بدون پروفایل، صفحات را خالی نشان میدهد و
|
||||||
|
باگهای واقعی را پنهان میکند. برای هر پرسونا اینها باید پر باشند:
|
||||||
|
|
||||||
|
| پرسونا | حداقل پروفایل لازم |
|
||||||
|
|---|---|
|
||||||
|
| `doctor_solo` / `doctor_member` / `clinic_doctor` | نام، تخصص، آدرس مطب، برنامهٔ کاری هفتگی، حداقل یک خدمت با تعرفه، حداقل یک بیمه |
|
||||||
|
| `clinic` | نام کلینیک، شهر، آدرس، حداقل یک پزشک عضو، حداقل یک خدمت |
|
||||||
|
| `secretary` / `secretary_clinic` | اتصال به پزشک/کلینیک + سطح دسترسیاش |
|
||||||
|
| `representation` | شهر تخصیصیافته |
|
||||||
|
| `patient` | نام، و حداقل یک نوبت رزروشده (برای اینکه صفحات خالی نباشند) |
|
||||||
|
| `unclaimed_doctor` | پروفایل پزشک بدون کاربرِ تصاحبکننده |
|
||||||
|
|
||||||
|
بعد از ساخت، پرشدن را تأیید کن — نه با حدس، با درخواست:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node .claude/skills/qa-clinicpro/driver.mjs api GET /api/v1/doctor/profile --as doctor_solo
|
||||||
|
```
|
||||||
|
|
||||||
|
**۰.۵ — تعیین سطح دسترسی.** ماتریس را از کد دربیاور، نه از ذهنت:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -n "RoleRoute\|allowedRoles\|element=" assets/admin/App.tsx # مسیرهای فرانت
|
||||||
|
grep -rn "IsGranted" src/*/Controller/ | sed 's/.*IsGranted(//' # گاردهای بکاند
|
||||||
|
```
|
||||||
|
|
||||||
|
از این دو، جدول `مسیر → نقشهای مجاز` را بساز و در گزارش بیاور. بعد برای هر اندپوینت
|
||||||
|
حساس با `authz` (بخش ۳) تأییدش کن. **اختلاف بین ماتریسِ کد و خروجی `authz` = باگ**،
|
||||||
|
حتی اگر خروجی `authz` سختگیرانهتر باشد.
|
||||||
|
|
||||||
|
**۰.۶ — دروازهٔ خروج.** تا وقتی `roles` برای همهٔ پرسوناها توکن برمیگرداند و ماتریس
|
||||||
|
نوشته شده، به فاز بعد نرو. اگر پرسونایی ساخته نشد، طبق بخش «وقتی به مانع خوردی»
|
||||||
|
خودت رفعش کن؛ رها کردنش یعنی آن نقش اصلاً تست نشده.
|
||||||
|
|
||||||
### ۱. بازدید از صفحه — اسکرینشات + خطاها
|
### ۱. بازدید از صفحه — اسکرینشات + خطاها
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -152,6 +240,52 @@ AUTHZ GET /api/v1/admin/users
|
|||||||
هر ۲۰۰ غیرمنتظره در این جدول = یک باگ Critical. اگر `anonymous` هم ۲۰۰ گرفت، درایور
|
هر ۲۰۰ غیرمنتظره در این جدول = یک باگ Critical. اگر `anonymous` هم ۲۰۰ گرفت، درایور
|
||||||
هشدار میدهد.
|
هشدار میدهد.
|
||||||
|
|
||||||
|
#### ۳.۱ جاروی کامل ماتریس — اجباری، نه نمونهای
|
||||||
|
|
||||||
|
`authz` خودش همهٔ پرسوناها را میزند، پس **تست دسترسی نباید روی چند اندپوینت منتخب
|
||||||
|
بماند**. لیست اندپوینتها را از روتر بگیر و همه را جارو کن:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ddev exec php bin/console debug:router --format=json \
|
||||||
|
| node -e 'const r=JSON.parse(require("fs").readFileSync(0));
|
||||||
|
for (const [n,v] of Object.entries(r))
|
||||||
|
if (v.path.startsWith("/api/v1") && !v.path.includes("{"))
|
||||||
|
console.log(v.method.split("|")[0].replace("ANY","GET"), v.path);' \
|
||||||
|
| while read m p; do
|
||||||
|
node .claude/skills/qa-clinicpro/driver.mjs authz "$m" "$p"
|
||||||
|
done | tee /tmp/qa-authz-matrix.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
روی این DB حدود **۱۶۸ مسیر بدون پارامتر** برمیگردد و `authz` برای هر مسیر بهازای هر
|
||||||
|
پرسونا دوباره لاگین میکند (≈۲۲۰۰ درخواست) — چند دقیقه طول میکشد، پس در پسزمینه
|
||||||
|
اجرایش کن و بعد فایل را بخوان. دو تله در خواندن خروجی:
|
||||||
|
|
||||||
|
- **۴۲۲ روی مسیرهای POST طبیعی است** (بدنه خالی فرستاده شده) و باگ نیست؛ چیزی که مهم
|
||||||
|
است تمایز ۴۰۱/۴۰۳ از بقیه است. اگر نقشی بهجای ۴۰۳ یک ۴۲۲ گرفت، یعنی **گارد بعد از
|
||||||
|
اعتبارسنجی اجرا شده** — همان هم یافته است.
|
||||||
|
- **مسیرهای عمومی** (لاگین، ثبتنام، لیست شهرها) قاعدتاً برای `anonymous` هم ۲۰۰اند؛
|
||||||
|
اول با `config/packages/security.yaml` تطبیق بده، بعد ادعای نشت کن.
|
||||||
|
|
||||||
|
اندپوینتهای پارامتردار (`{uuid}`) از این حلقه میافتند — آنها را دستی و با
|
||||||
|
**شناسهٔ متعلق به پرسونای دیگر** بزن، چون همانجاست که IDOR پیدا میشود:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# uuid پزشکِ دیگری را به پرسونای doctor_solo بده — باید ۴۰۳/۴۰۴ بگیرد، نه ۲۰۰
|
||||||
|
node .claude/skills/qa-clinicpro/driver.mjs authz GET /api/v1/doctor/<uuid-of-another-doctor>
|
||||||
|
```
|
||||||
|
|
||||||
|
سه الگویی که باید در `/tmp/qa-authz-matrix.txt` دنبالشان بگردی:
|
||||||
|
|
||||||
|
| یافته | معنی |
|
||||||
|
|---|---|
|
||||||
|
| `anonymous` = ۲۰۰ روی مسیر غیرعمومی | نشت داده — Critical |
|
||||||
|
| نقشی ۲۰۰ میگیرد که در ماتریس ۰.۵ نبود | گارد جا افتاده — Critical |
|
||||||
|
| ۲۰۰ روی uuidِ مستأجر دیگر | IDOR — Critical |
|
||||||
|
| نقشی ۴۰۳ میگیرد که طبق ماتریس باید ۲۰۰ بگیرد | یا گارد سختگیر است یا ماتریس غلط — بررسی کن |
|
||||||
|
| ۵۰۰ بهجای ۴۰۳ | گارد کار میکند ولی خطا مدیریت نشده — High |
|
||||||
|
|
||||||
|
**بدون این جدولِ کامل، فاز دسترسی تمامشده نیست.** خروجیاش را در گزارش نهایی بیاور.
|
||||||
|
|
||||||
### ۴. تست قرارداد API
|
### ۴. تست قرارداد API
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -207,16 +341,80 @@ SLOWEST API CALLS
|
|||||||
|
|
||||||
وقتی این skill فعال شد، مثل یک **مهندس ارشد تست** رفتار کن، نه فقط اجراکننده دستور:
|
وقتی این skill فعال شد، مثل یک **مهندس ارشد تست** رفتار کن، نه فقط اجراکننده دستور:
|
||||||
|
|
||||||
|
0. **Phase 0 را تمام کن** (بالا). بدون پرسوناهای کامل، هر تستی نتیجهٔ بیمعنی میدهد.
|
||||||
1. **اول سناریوی واقعی کاربر را بنویس**، بعد اجرا کن. مثال: ورود منشی → لیست نوبتها →
|
1. **اول سناریوی واقعی کاربر را بنویس**، بعد اجرا کن. مثال: ورود منشی → لیست نوبتها →
|
||||||
تغییر وضعیت یک نوبت → خروج → ورود مجدد → آیا تغییر ماند؟
|
تغییر وضعیت یک نوبت → خروج → ورود مجدد → آیا تغییر ماند؟
|
||||||
|
|
||||||
|
**پیمایش با هر پرسونا اجباری است.** بعد از Phase 0، برای *هر* پرسونا در جدول، وارد شو و
|
||||||
|
مسیرهای مجازش را طبق ماتریس ۰.۵ بگرد — نه فقط با `admin`. برای هر پرسونا حداقل:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
for p in admin clinic doctor_solo doctor_member clinic_doctor \
|
||||||
|
secretary secretary_clinic representation patient; do
|
||||||
|
node .claude/skills/qa-clinicpro/driver.mjs visit \
|
||||||
|
"https://clinic-pro.ddev.site/admin/dashboard" --as "$p" --out "/tmp/qa-$p.png"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
بعد **هر اسکرینشات را با Read باز کن و ببین** — و بخش `LANDING` را بخوان تا ریدایرکت
|
||||||
|
بیصدای نقش را نگیری. سه چیزی که فقط با مقایسهٔ بین پرسوناها پیدا میشوند:
|
||||||
|
|
||||||
|
- **نشت داده بین مستأجرها:** آیا `doctor_solo` دادهٔ بیمار پزشک دیگری را میبیند؟ آیا
|
||||||
|
`clinic` نوبتهای پزشک غیرعضو را میبیند؟ اینها همیشه Criticalاند.
|
||||||
|
- **صفحهٔ سفید بهجای «دسترسی ندارید»:** نقشی که نباید ببیند، باید پیام روشن بگیرد.
|
||||||
|
- **منوی سایدبار در برابر دسترسی واقعی:** آیتمی که نمایش داده میشود ولی به ۴۰۳
|
||||||
|
میخورد (یا برعکس: مسیر باز است ولی در منو نیست) باگ است.
|
||||||
2. برای هر بخش این حالتها را پوشش بده:
|
2. برای هر بخش این حالتها را پوشش بده:
|
||||||
Happy Path · ورودی نامعتبر · داده خالی · داده خیلی زیاد (لیست ۱۰٬۹۳۲ کاربری) ·
|
Happy Path · ورودی نامعتبر · داده خالی · داده خیلی زیاد (لیست ۱۰٬۹۳۲ کاربری) ·
|
||||||
شرایط مرزی · خطای شبکه · هر پنج نقش · دسکتاپ ۱۴۴۰ و موبایل ۳۹۰.
|
شرایط مرزی · خطای شبکه · **همهٔ پرسوناها** · دسکتاپ ۱۴۴۰ و موبایل ۳۹۰.
|
||||||
3. **هیچ چیز را حدس نزن.** ادعای بدون خروجی دستور، ادعا نیست.
|
3. **هیچ چیز را حدس نزن.** ادعای بدون خروجی دستور، ادعا نیست.
|
||||||
4. **قبل از گزارش، باگ را دوباره تکرار کن.** همان دستور را دوباره بزن؛ اگر تکرار نشد،
|
4. **قبل از گزارش، باگ را دوباره تکرار کن.** همان دستور را دوباره بزن؛ اگر تکرار نشد،
|
||||||
flaky بودنش را بنویس نه خودِ باگ را.
|
flaky بودنش را بنویس نه خودِ باگ را.
|
||||||
5. باگهای کوچک UI را هم گزارش کن، ولی باگهای Business Logic اولویت بالاترند.
|
5. باگهای کوچک UI را هم گزارش کن، ولی باگهای Business Logic اولویت بالاترند.
|
||||||
|
|
||||||
|
### وقتی به مانع خوردی — رفعش کن، بعد برو تست بعدی
|
||||||
|
|
||||||
|
QA اینجا فقط گزارشنویس نیست. هر جا اجرای تست گیر کرد، **مثل یک دولوپر ارشد
|
||||||
|
Symfony/React خودت مشکل را حل کن**، تأیید کن که حل شده، و تست را از همانجا ادامه بده.
|
||||||
|
توقف روی اولین مانع یعنی بقیهٔ نقشها هیچوقت تست نمیشوند.
|
||||||
|
|
||||||
|
روال ثابت هر مانع:
|
||||||
|
|
||||||
|
```
|
||||||
|
بازتولید → ریشهیابی (نه علامت) → اصلاح → اثبات اصلاح → ثبت → ادامهٔ همان تست
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **ریشه را پیدا کن، نه علامت را.** `visit` صفحهٔ سفید داد؟ اول `CONSOLE ERRORS` و
|
||||||
|
`NETWORK FAILURES`، بعد فایل سورس صفحه (`redesign-page/driver.mjs inspect`)، بعد
|
||||||
|
کنترلر مربوطه. اصلاح باید در همان لایهای باشد که علت آنجاست.
|
||||||
|
2. **طبق قواعد پروژه اصلاح کن**، نه با وصلهٔ سریع:
|
||||||
|
- بکاند: `extends BaseController`، خطا با `AppException(ErrorCodes::…)`، کد SOLID،
|
||||||
|
تغییر entity ⟵ `doctrine:migrations:diff` + `migrate`.
|
||||||
|
- فرانت: TanStack Query برای دادهٔ سرور، کامپوننتهای `components/ui/`، توکنهای
|
||||||
|
`styles.css` (هیچ hex هاردکد)، رشتههای فارسی.
|
||||||
|
- اندپوینت عوض شد ⟵ همان جلسه `docs/api/<domain>.md` را بهروز کن (قاعدهٔ ثابت پروژه).
|
||||||
|
3. **اثبات کن.** همان دستوری که شکست خورده بود را دوباره بزن و خروجی سالمش را نشان بده.
|
||||||
|
بعد `ddev exec php bin/phpunit` و در صورت تغییر فرانت `npx tsc --noEmit` را اجرا کن
|
||||||
|
تا مطمئن شوی چیزی نشکستهای.
|
||||||
|
4. **ثبت کن.** هر اصلاح یک ورودی در بخش «Fixes Applied» گزارش نهایی میگیرد:
|
||||||
|
مانع · ریشه · فایلهای تغییریافته · دستور اثبات.
|
||||||
|
|
||||||
|
**مرزهایی که رد نمیکنی:**
|
||||||
|
|
||||||
|
- **باگ محصول را بیصدا رفع نکن.** اگر مانع خودش یک باگ واقعی محصول است، هم Bug Report
|
||||||
|
را بنویس هم اصلاح را — نه فقط اصلاح. گزارش، خروجی کار است.
|
||||||
|
- **هرگز برای سبزشدن تست، دسترسی را باز نکن.** اگر نقشی ۴۰۳ میگیرد و تو انتظار ۲۰۰
|
||||||
|
داری، پیشفرض این است که **انتظارت غلط است**. `IsGranted` یا `RoleRoute` را فقط وقتی
|
||||||
|
عوض کن که از روی کد ثابت کرده باشی آن نقش باید دسترسی داشته باشد، و دلیلش را بنویس.
|
||||||
|
همین قاعده برای حذف اعتبارسنجی ورودی هم هست.
|
||||||
|
- **دادهٔ تست را با تغییر محصول نساز.** کمبود دادهٔ پرسونا را با seed درست کن، نه با
|
||||||
|
نرمکردن یک قاعدهٔ کسبوکار.
|
||||||
|
- **مهاجرت مخرب نزن.** روی DB لوکالِ پر (۱۰٬۹۳۲ کاربر) `doctrine:schema:drop` یا
|
||||||
|
مهاجرتی که ستون پرداده را میاندازد، ممنوع.
|
||||||
|
- **اگر اصلاح از تست بزرگتر شد** (بازطراحی معماری، تغییر شکستدهندهٔ قرارداد API که
|
||||||
|
`nobat724_front` و `clinic-pro-tauri` هم مصرفش میکنند)، دست نگه دار: باگ را با
|
||||||
|
اصلاح پیشنهادی گزارش کن، آن یک تست را `SKIPPED` علامت بزن، و **برو تست بعدی**.
|
||||||
|
|
||||||
### فرمت Bug Report
|
### فرمت Bug Report
|
||||||
|
|
||||||
هر یافته را با این قالب بنویس (فارسی):
|
هر یافته را با این قالب بنویس (فارسی):
|
||||||
@@ -253,6 +451,19 @@ node .claude/skills/redesign-page/driver.mjs inspect "https://clinic-pro.ddev.si
|
|||||||
۱. خلاصه وضعیت کلی · ۲. تعداد باگها · ۳. لیست بر اساس Severity ·
|
۱. خلاصه وضعیت کلی · ۲. تعداد باگها · ۳. لیست بر اساس Severity ·
|
||||||
۴. باگهایی که باید فوری رفع شوند · ۵. پیشنهاد بهبود کیفیت.
|
۴. باگهایی که باید فوری رفع شوند · ۵. پیشنهاد بهبود کیفیت.
|
||||||
|
|
||||||
|
بهعلاوه این سه بخش که از قواعد بالا میآیند:
|
||||||
|
|
||||||
|
**۶. Fixes Applied** — هر مانعی که خودت رفع کردی:
|
||||||
|
|
||||||
|
| مانع | ریشه | فایلهای تغییریافته | دستور اثبات |
|
||||||
|
|---|---|---|---|
|
||||||
|
|
||||||
|
**۷. ماتریس دسترسی** — جدول کامل `مسیر × پرسونا` از بخش ۳.۱، با اختلافهای
|
||||||
|
ماتریسِ کد و رفتار واقعی مشخصشده.
|
||||||
|
|
||||||
|
**۸. پوشش** — کدام پرسونا چه چیزی تست شد، و هر `SKIPPED` با دلیلش. اگر نقشی تست نشد
|
||||||
|
باید اینجا صریح بیاید؛ گزارشِ ساکت بدتر از گزارش ناقص است.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Gotchas
|
## Gotchas
|
||||||
|
|||||||
@@ -25,9 +25,13 @@ const CHROME = process.env.CHROME_BIN
|
|||||||
const PORT = Number(process.env.CDP_PORT ?? 9444);
|
const PORT = Number(process.env.CDP_PORT ?? 9444);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local QA accounts, one per role. Passwords were set deliberately for testing
|
* Local QA personas — one per distinct authorization identity in the product,
|
||||||
* (see SKILL.md § Test accounts); the doctor account predates that and still
|
* not merely one per ROLE_* constant: an independent doctor and a clinic-member
|
||||||
* uses mobile-as-password. TEST_USERS.md is stale — its accounts do not exist.
|
* doctor carry the same role but see different data, so each gets its own row.
|
||||||
|
*
|
||||||
|
* The first five predate this list and are known to exist; the rest are
|
||||||
|
* provisioned by SKILL.md § Phase 0 and report `✗` from `driver.mjs roles`
|
||||||
|
* until they are. TEST_USERS.md is stale — its accounts do not exist.
|
||||||
*/
|
*/
|
||||||
const ROLES = {
|
const ROLES = {
|
||||||
admin: ['09120671756', 'QaTest@1234'],
|
admin: ['09120671756', 'QaTest@1234'],
|
||||||
@@ -35,6 +39,15 @@ const ROLES = {
|
|||||||
secretary: ['09123456778', 'QaTest@1234'],
|
secretary: ['09123456778', 'QaTest@1234'],
|
||||||
doctor: ['09390039833', '09390039833'],
|
doctor: ['09390039833', '09390039833'],
|
||||||
representation: ['09124000001', '09124000001'],
|
representation: ['09124000001', '09124000001'],
|
||||||
|
|
||||||
|
// Provisioned by Phase 0. Reserved QA range 0912900000x, password QaTest@1234.
|
||||||
|
doctor_solo: ['09129000001', 'QaTest@1234'], // own office, no clinic
|
||||||
|
doctor_member: ['09129000002', 'QaTest@1234'], // member of a clinic
|
||||||
|
clinic_doctor: ['09129000003', 'QaTest@1234'], // ROLE_CLINIC + ROLE_DOCTOR
|
||||||
|
secretary_clinic: ['09129000004', 'QaTest@1234'], // secretary of a clinic
|
||||||
|
unclaimed_doctor: ['09129000005', 'QaTest@1234'], // imported, unclaimed profile
|
||||||
|
patient: ['09129000006', 'QaTest@1234'], // ROLE_USER only
|
||||||
|
importer: ['09129000007', 'QaTest@1234'],
|
||||||
};
|
};
|
||||||
|
|
||||||
// ddev serves a locally-signed cert Node's fetch refuses. Relax TLS only for it.
|
// ddev serves a locally-signed cert Node's fetch refuses. Relax TLS only for it.
|
||||||
|
|||||||
Reference in New Issue
Block a user