Adds SlotModeFrozenTest (#[Group('slot-mode-frozen')]) locking three things
against the multi-resource booking phase:
- GET /api/v1/appointment-slots response shape
- GET /api/v1/appointment-settings/month-availability/{uuid} response shape
- public method signatures of SlotCalculatorService
Fixtures are structural, not raw snapshots: a fixed past date is rejected by
isWithinBookingWindow so an empty snapshot would prove nothing. Instead a
deterministic schedule on a computed near-future date, with epoch/uuid values
normalized to placeholders. What stays locked is the contract itself: keys,
ordering, types and local times.
No production code touched.
Task: docs/new_feture/taskes/task-00-service-mode-completion/
Slot-mode contract: unchanged (--group=slot-mode-frozen green, 3 tests)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
31 KiB
راهبر اجرای تسکهای موتور نوبتدهی — یک تسک در هر اجرا
پروژه
clinicpro (بکاند + پنل ادمین)
پرامپت همتا برای سایت عمومی: nobat724_front/.claude/prompt/booking-engine-task-00b-service-mode.md
(همین راهبر وقتی به تسک ۰۰ب برسد، تحویلش میدهد و میایستد.)
زمینه
docs/new_feture/taskes/ شانزده تسک برای پیادهسازی
مستند موتور نوبتدهی دارد. هر تسک یک
پوشه با شش فایل است و خودش یک پرامپت کامل است: task.md (دامنه و معیار پذیرش)،
architecture.md (فایلها و سرویسها)، database.md (جداول و migration)،
implementation_notes.md (نکات و edge case و تست)، checklist.md (وضعیت)، و برای
تسکهای پیچیده user_flow.md.
جمع زمان تخمینی ۲۱۴ تا ۲۵۶ ساعت است. هیچ اجرایی نمیتواند همه را در یک نشست تمام کند.
پس این پرامپت خودش قابلیت نیست — راهبر است. هر اجرا:
وضعیت را از checklist.md ها بخوان
→ تسک بعدی واجد شرایط را انتخاب کن
→ همان یک تسک را کامل انجام بده (پیادهسازی + تست + مستند + چکلیست)
→ commit + graphify update
→ بایست و بگو تسک بعدی چیست
همین پرامپت را دوباره اجرا کن تا تسک بعدی برود. تا وقتی همهٔ چکلیستها ✅ نشدهاند، کار تمام نیست.
مشکل / هدف
هدف: یک مسیر اجرای تکرارشونده و ایمن که شانزده تسک را به ترتیب وابستگی، یکییکی و بدون از دست دادن وضعیت پیش ببرد — طوری که هر اجرا مستقل باشد و قطع شدن وسط کار، کار انجامشده را از بین نبرد.
چرا این شکل و نه یک پرامپت غول: وضعیت در checklist.md روی دیسک زندگی میکند، نه در
context. اجرای بعدی همان فایل را میخواند و میفهمد کجا مانده. هزینهٔ این طراحی یک
مرحلهٔ «خواندن وضعیت» در ابتدای هر اجراست؛ سودش این است که هیچ اجرایی به context اجرای
قبلی وابسته نیست.
معیار پذیرش
معیار پذیرش این راهبر، رفتار خودِ راهبر است. معیار پذیرش هر تسک در task.md همان تسک
است و اینجا تکرار نمیشود.
- ✅ موفق: اجرا با شناسایی وضعیت شروع میشود (جدول ۱۶ تسک با ✅/🔄/⏳)، دقیقاً یک تسک
انتخاب میشود، همهٔ ردیفهای
checklist.mdآن تسک به ✅ میرسند،bin/phpunitو--group=slot-mode-frozenسبزند،docs/api/*بهروز است، یک commit زده میشود،graphify update .اجرا میشود، و اجرا با اعلام تسک بعدی تمام میشود. - ✅ موفق (ازسرگیری): اجرای دوم روی همان مخزن، تسک تمامشده را دوباره انجام نمیدهد و مستقیم سراغ تسک بعدی میرود.
- ✅ موفق (نیمهکاره): اگر چکلیستی ردیف 🔄 دارد، همان تسک ادامه داده میشود، نه تسک بعدی.
- ❌ خطا: اگر تسکی وابستگیاش ✅ نیست → اجرا شروع نمیشود؛ پیام روشن با نام تسک پیشنیاز و توقف.
- ❌ خطا: اگر
--group=slot-mode-frozenقرمز شد → توقف کامل، rollback تغییرات آن مرحله، گزارش دقیق کدام fixture شکست. fixture هرگز بهروز نمیشود. - ❌ خطا: اگر تستی سبز نشد → تسک
completedنمیشود؛ ردیف چکلیست 🔄 میماند و اجرا با گزارش خطا تمام میشود. تسک بعدی شروع نمیشود. - ⚠️ مرزی: همهٔ ۱۶ چکلیست ✅ → پیام «همهٔ تسکها تمام شدهاند» و توقف بدون تغییر.
- ⚠️ مرزی: تسک انتخابشده ۰۰ب است (پروژهٔ دیگر) → اجرا کد نمیزند؛ دستور اجرای
پرامپت
nobat724_frontرا میدهد و میایستد. - ⚠️ مرزی: کاربر شمارهٔ تسک را صریح داد (
/run-prompt … --task=05) → همان تسک، ولی وابستگیها همچنان بررسی میشوند و اگر ناقص بودند توقف. - ⚠️ مرزی: ردیفی از چکلیست به دلیل موجه قابل انجام نیست → ⏳ میماند با دلیل مکتوب و تسک مقصد در ستون یادداشت. ⏳ بیدلیل = تسک تمام نشده.
فایلهای مرتبط
| فایل | نقش |
|---|---|
docs/new_feture/taskes/README.md |
فهرست ۱۶ تسک، وابستگیها، ترتیب اجرا |
docs/new_feture/taskes/00-current-state-report.md |
تحلیل شکاف وضعیت فعلی در برابر مستند |
docs/new_feture/taskes/_shared/red-lines.md |
⛔ قواعد قفلشده — منطق اسلاتی دستکاری نمیشود |
docs/new_feture/taskes/_shared/ui-conventions.md |
🎨 توکنها و کامپوننتهای اجباری |
docs/new_feture/taskes/_shared/definition-of-done.md |
☑️ نمادها و بازبینی پایانی |
docs/new_feture/taskes/task-XX-*/task.md |
دامنه و معیار پذیرش هر تسک |
docs/new_feture/taskes/task-XX-*/architecture.md |
فایلها، سرویسها، قواعد UI |
docs/new_feture/taskes/task-XX-*/database.md |
جداول، ایندکس، migration، backfill |
docs/new_feture/taskes/task-XX-*/implementation_notes.md |
edge case و فهرست تست |
docs/new_feture/taskes/task-XX-*/checklist.md |
وضعیت پایدار — منبع حقیقت پیشرفت |
docs/new_feture/taskes/task-XX-*/user_flow.md |
جریان کاربری (۰۰، ۰۰ب، ۰۵، ۰۶، ۰۷، ۱۲) |
CLAUDE.md · docs/architecture/tenancy.md |
قواعد ثابت پروژه |
وضعیت فعلی
هر شانزده checklist.md ساخته شده و همهٔ ردیفهایشان ⏳ است. هیچ تسکی شروع نشده.
ساختار ثابت هر چکلیست:
# چکلیست — تسک XX (عنوان)
**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** —
## ۰. خط سرخ
| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | |
...
## ۱. بکاند
## ۲. دیتابیس
## ۳. UI
## ۴. تست
## ۵. مستندات
## ۶. بازبینی پایانی
نمادها (از _shared/definition-of-done.md):
| نماد | معنی | اجازهٔ باقیماندن در پایان تسک |
|---|---|---|
| ✅ | انجامشده و تأییدشده | بله |
| 🔄 | در حال انجام | نه |
| ⏳ | انجامنشده | نه — مگر با دلیل مکتوب و تسک مقصد |
| ⚠️ | نیازمند بررسی یا تست | نه — باید تعیین تکلیف شود |
ترتیب و وابستگی (از README.md):
۰۰ ── ۰۰ب
│
├─ ۰۱ ─┬─ ۰۲ ── ۰۳ ─┐
│ └─ ۰۴ ── ۰۵ ─┴─ ۰۶ ── ۰۷ ─┬─ ۰۸ ─┬─ ۰۹ ── ۱۰
│ │ └─ ۱۱ ── ۱۲
│ ├─ ۱۳
│ └─ ۱۴
| تسک | پروژه | وابستگی |
|---|---|---|
| ۰۰ تکمیل نوبتدهی سرویسی | clinicpro |
— |
| ۰۰ب سازگارسازی سایت | nobat724_front |
۰۰ |
| ۰۱ شعبه و اتاق | clinicpro |
۰۰ |
| ۰۲ منبع، مهارت، استخر | clinicpro |
۰۱ |
| ۰۳ تقویم منبع | clinicpro |
۰۱، ۰۲ |
| ۰۴ کاتالوگ خدمات v2 | clinicpro |
۰۱ |
| ۰۵ بخشهای نوبت | clinicpro |
۰۲، ۰۴ |
| ۰۶ جستجوی وقت چندمنبعی | clinicpro |
۰۳، ۰۵ |
| ۰۷ رزرو موقت و ثبت | clinicpro |
۰۶ |
| ۰۸ قیمت و snapshot | clinicpro |
۰۴، ۰۷ |
| ۰۹ موتور قوانین | clinicpro |
۰۵، ۰۶، ۰۸ |
| ۱۰ فرم و sandbox قانون | clinicpro |
۰۹ |
| ۱۱ پکیج و دفتر اعتبار | clinicpro |
۰۸ |
| ۱۲ دوره درمان | clinicpro |
۰۷، ۱۱ |
| ۱۳ لغو، عدم حضور، انتظار | clinicpro |
۰۷ |
| ۱۴ رویدادها و بهرهوری | clinicpro |
۰۷ |
وظایف
⚠️ این هفت وظیفه مراحل یک اجرای راهبرند، نه هفت قابلیت مستقل.
todoرا از روی ردیفهایchecklist.mdتسکِ انتخابشده بساز، نه از روی این هفت مرحله.
۱. خواندن قواعد حاکم — پیش از هر چیز
سه سند را کامل بخوان و در همین اجرا اعمال کن:
docs/new_feture/taskes/_shared/red-lines.md
docs/new_feture/taskes/_shared/ui-conventions.md
docs/new_feture/taskes/_shared/definition-of-done.md
در تناقض با متن هر تسک، این سه برندهاند.
مهمترین بندشان:
- ⛔ منطق اسلاتی (
booking_mode = 'slot') در هیچ تسکی دستکاری نمیشود. فهرست فایلها و متدهای قفلشده درred-lines.mdاست. - 🎨 هر صفحه یا کامپوننت جدید عیناً با دیزاینسیستم موجود — توکنهای
assets/admin/styles.css، کامپوننتهایassets/admin/components/ui/، پنج قاعدهٔ غیرقابلمذاکره. - ☑️ هیچ تسکی بدون تکمیل چکلیستش تمام نیست.
نحوه تست: بعد از خواندن، در گزارش شروع بنویس کدام سه سند خوانده شد و مهمترین قید مربوط به تسک انتخابشده چیست (یک جمله).
۲. شناسایی وضعیت و انتخاب تسک
همهٔ چکلیستها را بخوان و وضعیت هر تسک را از ردیفهایش استنتاج کن، نه از خط «وضعیت کلی» (که ممکن است بهروز نشده باشد):
# فهرست چکلیستها به ترتیب
ls -1 docs/new_feture/taskes/*/checklist.md | sort
# شمارش نمادها per تسک — دیدِ سریع وضعیت
for f in docs/new_feture/taskes/*/checklist.md; do
echo "$(dirname "$f" | xargs basename): ✅=$(grep -c '| ✅ |' "$f") 🔄=$(grep -c '| 🔄 |' "$f") ⏳=$(grep -c '| ⏳ |' "$f") ⚠️=$(grep -c '| ⚠️ |' "$f")"
done
قاعدهٔ استنتاج:
تمامشده = هیچ ردیف 🔄 · هیچ ردیف ⚠️ · هیچ ردیف ⏳ بدون یادداشتِ دلیل
در جریان = حداقل یک ردیف 🔄 یا ⚠️
شروع نشده = همهٔ ردیفها ⏳ و هیچ یادداشتی
قاعدهٔ انتخاب، به همین ترتیب:
- اگر تسکی در جریان است → همان. (تسک نیمهکاره رها نمیشود.)
- وگرنه اولین تسکِ شروع نشده که همهٔ وابستگیهایش تمامشده اند.
- اگر کاربر
--task=XXداد → همان، ولی وابستگیها همچنان بررسی میشوند. - اگر همه تمامشدهاند → پیام و توقف.
- اگر تسک انتخابشده وابستگی ناقص دارد → توقف با نام تسک پیشنیاز.
جدول وضعیت را به کاربر نشان بده و تسک انتخابشده را اعلام کن:
📊 وضعیت تسکها
۰۰ تکمیل سرویسی ✅ تمامشده
۰۰ب سازگارسازی سایت ✅ تمامشده
۰۱ شعبه و اتاق 🔄 در جریان (۱۲/۳۸)
۰۲ منبع و مهارت ⏳ شروع نشده
…
🎯 تسک انتخابشده: ۰۱ — شعبه و اتاق (ادامهٔ کار نیمهکاره)
نحوه تست: دستور شمارش بالا را اجرا کن و خروجی واقعیاش را در گزارش بگذار. جدول نمایشدادهشده باید با آن خروجی بخواند.
۳. تحویل به پرامپت همتا اگر تسک ۰۰ب انتخاب شد
تسک ۰۰ب روی nobat724_front است و در این پروژه هیچ کدی ندارد.
اگر انتخاب ۰۰ب شد، هیچ فایلی را تغییر نده و این را چاپ کن و بایست:
🔀 تسک ۰۰ب روی پروژهٔ nobat724_front است.
اجرا کن: /run-prompt nobat724_front/.claude/prompt/booking-engine-task-00b-service-mode.md
بعد از تمام شدنش، همین راهبر را دوباره اجرا کن تا تسک ۰۱ برود.
نحوه تست: موقتاً همهٔ ردیفهای task-00-service-mode-completion/checklist.md را ✅ کن،
راهبر را اجرا کن، و ببین همین پیام چاپ میشود و هیچ فایلی در src/ عوض نمیشود.
بعد تغییر موقت را برگردان.
۴. اجرای تسک انتخابشده — یکی، کامل
چهار (یا پنج) فایل تسک را کامل بخوان:
task-XX-*/task.md ← دامنه، endpoint ها، معیار پذیرش
task-XX-*/architecture.md ← فایلها، سرویسها، الگوها، قواعد UI
task-XX-*/database.md ← جداول، ایندکس، migration، backfill
task-XX-*/implementation_notes.md ← edge case ها، فهرست تست، تلههای مشخص
task-XX-*/user_flow.md ← اگر وجود دارد
بعد کد واقعی مرتبط را بخوان — هیچ فرضی از حافظه (guidelines §۱).
سپس todo بساز: یک آیتم به ازای هر ردیفِ غیر-✅ چکلیست، مرتب بر اساس بخش
(۰ خط سرخ → ۱ بکاند → ۲ دیتابیس → ۳ UI → ۴ تست → ۵ مستندات → ۶ بازبینی پایانی).
اجرای هر ردیف با همان هفتمرحلهٔ run-prompt:
① تحلیل ② طراحی ③ پیادهسازی ④ تست ⑤ رفع خطا ⑥ مستندسازی ⑦ چکلیست + گزارش
قواعدی که در این مرحله شکستنی نیستند:
- بخش ۰ چکلیست اول از همه. خط سرخها پیش از هر کد بررسی میشوند. در تسک ۰۰ این یعنی
ساختن
SlotModeFrozenTestو سه fixture قبل از هر تغییر — وگرنه snapshot وضعیت تغییریافته گرفته میشود و چیزی را تضمین نمیکند. - یک ردیف در هر لحظه
in_progress. - ردیف فقط با هر سه ✅ میشود: پیادهسازی + تست سبز + مستند بهروز.
- خطا = توقف کامل. هیچ ردیفی روی خرابهٔ ردیف قبلی ساخته نمیشود.
- کشف کار جدید (باگ جانبی، وابستگی پنهان) → ردیف جدید به همان
checklist.mdاضافه کن و به کاربر بگو. انجام بیصدا ممنوع.
نحوه تست: دستورهای هر پروژه بعد از هر ردیفِ منطقدار:
ddev exec php bin/console cache:clear
ddev exec php bin/console doctrine:migrations:diff --no-interaction # اگر entity عوض شد
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
ddev exec php bin/phpunit tests/<Domain> # تست همان تسک
ddev exec php bin/phpunit --group=slot-mode-frozen # ⛔ بعد از هر ردیف
ddev exec php vendor/bin/phpstan analyse src/<Domain>
npx tsc --noEmit --project tsconfig.json # اگر tsx عوض شد
yarn dev # بررسی خطای build
yarn test
برای هر endpoint، تست واقعی با داده واقعی — نه فقط php -l. کاربر تست:
09390039833 / 09390039833 (اگر کار نکرد، اعتبارهای per-نقش با QaTest@1234).
۵. بهروزرسانی زندهٔ checklist.md
چکلیست حافظهٔ بیناجرایی است. اگر بهروز نشود، اجرای بعدی کار انجامشده را دوباره انجام میدهد.
قواعد نوشتن:
- ردیف را همان لحظه که شروع میکنی
⏳ → 🔄کن، نه در پایان تسک - تمام شد →
🔄 → ✅با یادداشت کوتاه اگر چیزی برای گفتن هست (مسیر فایل، عدد اندازهگیریشده) - شکست خورد یا بلاک شد →
⚠️با دلیل در ستون یادداشت - به تعویق افتاد →
⏳با دلیل + تسک مقصد در یادداشت.⏳بیدلیل = تسک تمام نشده. - خط سربرگ را هم بهروز کن:
**وضعیت کلی:** 🔄 در حال انجام · **آخرین بازبینی:** ۱۴۰۵/۰۵/۰۳
پیش از رفتن به وظیفهٔ ۶، بخش ۶ (یا ۷/۸ بسته به تسک) بازبینی پایانی را ردیفبهردیف اجرا کن. ردیفهای مشترک همهٔ تسکها:
همهٔ ردیفهای بالا وضعیت نهایی دارند (هیچ 🔄 و ⏳ بیدلیل)
ddev exec php bin/phpunit کامل سبز
ddev exec php bin/phpunit --group=slot-mode-frozen سبز
ddev exec php vendor/bin/phpstan analyse بدون خطای جدید
npx tsc --noEmit بدون خطا
yarn test سبز
TenantSchemaCoverageTest + TenantLookupInventoryTest سبز
docs/api/* بهروز شد
چکلیست UI کامل شد (اگر تسک صفحه دارد)
nobat724_front و clinic-pro-tauri دستی بررسی شدند
commit شد، سپس graphify update .
موارد بهتعویقافتاده با دلیل و تسک مقصد ثبت شدند
ردیف «دو کلاینت دیگر» در build هیچکدام خطا نمیدهد — بررسی فقط دستی ممکن است (guidelines §۳). نتیجه را با ذکر فایلهای بررسیشده گزارش بده، نه با «بررسی شد».
نحوه تست: بعد از بهروزرسانی، دستور شمارش وظیفهٔ ۲ را دوباره اجرا کن. تسک باید
✅=<همه> 🔄=0 ⏳=0 ⚠️=0 بدهد.
۶. Commit و بهروزرسانی گراف
ترتیب مهم است: اول commit، بعد graphify update — وگرنه گراف وضعیت کامیتنشده را
ایندکس میکند.
git add -A
git commit -m "$(cat <<'EOF'
feat(booking): <عنوان انگلیسی تسک>
<دو-سه خط: چه چیزی اضافه شد، چه چیزی عمداً دستنخورده ماند>
Task: docs/new_feture/taskes/task-XX-<name>/
Slot-mode contract: unchanged (--group=slot-mode-frozen green)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
EOF
)"
graphify update .
پیام کامیت انگلیسی (قاعدهٔ پروژه). خط Slot-mode contract اجباری است — رد مکتوبِ
اینکه خط سرخ رعایت شده.
اگر روی برنچ main هستی، اول برنچ بساز:
git checkout -b feat/booking-engine-task-XX
نحوه تست: git log --oneline -1 و git status را در گزارش بگذار.
۷. گزارش پایانی و اعلام تسک بعدی
اجرا با این قالب تمام میشود و تسک بعدی شروع نمیشود:
✅ تسک XX — <عنوان> تمام شد
پیادهسازی
• <سه تا پنج خط: چه ساخته شد، با مسیر فایل>
تست
• bin/phpunit : <N> تست، سبز
• --group=slot-mode-frozen : سبز
• phpstan / tsc / yarn test : سبز
• تستهای جدید این تسک : <فهرست کوتاه>
مستندات
• <فایلهای docs/api/* و docs/architecture/* که عوض شدند>
خط سرخ
• منطق اسلاتی دستنخورده — <یک جمله شاهد، مثلاً: هیچ متد SlotCalculatorService عوض نشد>
کلاینتهای دیگر
• nobat724_front : <چه بررسی شد و نتیجه>
• clinic-pro-tauri: <همان>
به تعویق افتاد (اگر هست)
• <ردیف> — دلیل: <…> — تسک مقصد: <XX>
commit: <hash کوتاه> · graphify: بهروز شد
────────────────────────────────
🎯 تسک بعدی: XX — <عنوان> (وابستگیها: ✅)
اجرا کن: /run-prompt clinicpro/.claude/prompt/booking-engine-task-runner.md
اگر تسک ناتمام ماند، بهجای ✅ بنویس:
⛔ تسک XX ناتمام ماند
بلاککننده: <چه چیزی و کجا>
ردیفهای باقی: <فهرست با وضعیت>
چکلیست بهروز شد؛ اجرای بعدی از همینجا ادامه میدهد.
نحوه تست: گزارش باید با خروجی واقعی دستورها بخواند. عدد تست ساختگی ننویس.
نکات مهم
خط سرخ — تنها چیزی که هیچ تسکی نمیتواند نقض کند
booking_mode = 'slot' منطق تولیدیِ زنده است. _shared/red-lines.md فهرست دقیق دارد؛
خلاصهاش:
| قفل | یعنی |
|---|---|
هفت متد عمومی SlotCalculatorService |
امضا و رفتار عوض نمیشود |
GET /api/v1/appointment-slots |
قرارداد request/response |
GET /api/v1/appointment-settings/month-availability/{doctorUuid} |
قرارداد |
Appointment::active_slot_key و refreshActiveSlotKey() |
مکانیزم یکتایی موجود |
AppointmentRepository::isSlotTaken |
امضا و معنا |
WeeklySchedule::DEFAULT_META['booking_mode'] |
مقدار slot میماند |
مجاز: افزودن متد جدید · کلاس موازی · ستون تهیپذیر · کلید جدید در meta با حفظ پیشفرض
ممنوع: تغییر امضای متد موجود · refactor «یکدستسازی» · اعمال قوانین جدید روی حالت slot
fixture های tests/Appointment/fixtures/slot-mode-contract.json و
month-availability-contract.json و slot-calculator-signatures.php read-only اند.
اگر تست قرمز شد، کد برمیگردد، نه fixture. تسک ۰۰ آنها را میسازد؛ هیچ تسک دیگری
اجازهٔ بهروزرسانیشان را ندارد.
فاز ۰ اختیاری نیست
تسک ۰۰ و ۰۰ب پیشنیاز واقعیاند، نه توصیه. حالت service امروز پنج شکاف در چرخهٔ عمر
نوبت دارد (ویرایش، جابهجایی، رزرو، پنل بیمار، دیزاینسیستم سایت — جزئیات در
00-current-state-report.md بخش ۲-۵ب). اگر حالت resource (تسک ۰۶) روی این پایه ساخته
شود، هر باگ موجود به موتور جدید ارث میرسد و تشخیص منبعش غیرممکن میشود.
دیزاینسیستم — هر صفحهٔ جدید
_shared/ui-conventions.md کامل است. پنج قاعدهای که رعایت نکردنشان یعنی رد شدن ردیف:
SearchableSelect، هرگز<select>بومی- زیرصفحهها
backToیا<BackButton fallback="…" />— دکمهٔ دستساز نه - وضعیت لیست (جستجو/فیلتر/صفحه) در URL با
hooks/useUrlState.ts، نهuseState - داده فقط TanStack Query از
lib/api.ts؛ استخراج: paginated →data?.data+data?.meta?.totalRecords· single →data?.data· Category →data?.data?.data ?? [] - فرم با React Hook Form + Zod
و: هیچ رنگ/شعاع/سایهٔ hard-code — همه از توکنهای :root در assets/admin/styles.css.
دارکمود ([data-theme="dark"]) و حالت فشرده ([data-density="compact"]) بررسی شوند.
مقدار hex در دارکمود میشکند.
پیش از ساختن هر کامپوننت، assets/admin/components/ui/ را بگرد. ساختن نسخهٔ موازیِ
DataTable/Modal/ConfirmDialog/PageHeader/StatCard/StatusBadge/Pagination/
PersianDatePicker/PriceInput رد میشود.
قواعد ثابت پروژه در هر تسک
از CLAUDE.md و docs/architecture/tenancy.md:
- entity جدید یا
TenantOwnedTraitمیگیرد یا با دلیل درApp\Shared\Tenant\GlobalTablesثبت میشود؛TenantSchemaCoverageTestهر دو حالت را اجبار میکند entity_type, entity_idستونهای اول هر ایندکس ترکیبیِ لیست — وگرنه MariaDB برای شرطTenantFilterاز ایندکس استفاده نمیکند- هر uuid که از request میآید با
App\Shared\Tenant\TenantOwnershipCheckerسنجیده میشود؛TenantLookupInventoryTestشمارنده per-file دارد وfindByUuidتازه تست را قرمز میکند - timestamp ها
intیونیکس، نهDateTime؛ نمایش شمسی فقط در UI باformatDate - کنترلر نازک ·
extends BaseController·$this->success()/paginated()/error() - خطا با
throw new AppException(ErrorCodes::ERR_XXX, null, $status)؛ کد و پیام فارسی درsrc/Shared/Constant/ErrorCodes.php - لیستهای ادمین با
->getArrayResult() - API جدید فقط وقتی هیچ endpoint موجودی — حتی با توسعه — کافی نباشد؛ دلیلش نوشته شود
- هر endpoint جدید یا تغییریافته →
docs/api/*.mdدر همان نشست
الگوهای معماری که تسکها تصریح کردهاند
| الگو | تسک | دلیل انتخاب (در همان تسک مکتوب است) |
|---|---|---|
| Strategy + tagged_iterator | ۰۶ ResourcePickerInterface |
افزودن استراتژی پنجم نباید کلاس موجود را عوض کند (OCP) |
| Repository + سرویس واحدِ نویسنده | ۰۷ OccupancyWriter |
تنها نقطهٔ نوشتن در resource_occupancy |
| Registry بسته | ۰۹ FieldRegistry/OperatorRegistry/EffectRegistry |
مستند بند ۸: کد دلخواه در قانون ممنوع، وگرنه جستجوی وقت کند میشود |
| Outbox | ۱۴ DomainEventPublisher |
commit اتمی رویداد با کار؛ نه «پیامک رفته و نوبت نیست» |
| Ledger (دفتر) نه شمارنده | ۱۱ SessionCreditLedger |
مستند بند ۱۲: با شمارنده، اولین اشتباه غیرقابلردیابی است |
| کلید یکتای سطل زمانی | ۰۷ resource_occupancy_slot |
MariaDB EXCLUDE ندارد؛ تضمین از دیتابیس نه از کد |
اینها تصمیم گرفتهشدهاند، نه پیشنهاد. اگر در اجرا به مشکل خوردی، قبل از تغییر الگو دلیل را به کاربر بگو و تعیین تکلیف بخواه (guidelines §۶).
تسکهای پرخطر — جای کندی و دقت
| تسک | ریسک | کاری که باید بکنی |
|---|---|---|
| ۰۰ | fixture بعد از تغییرات ساخته شود | fixture اول، بعد کد |
| ۰۶ | I/O داخل حلقه → جستجو کند | AvailabilityPerformanceTest تعداد کوئری را قفل میکند: ≤۵ |
| ۰۷ | تست همزمانی با mock بیارزش است | دو اتصال DBAL واقعی، assertSame(1, ok1+ok2) |
| ۰۹ | spacing per-slot حلقه بزند |
forbiddenRanges() کوئریمحور؛ AvailabilityPerformanceTest باید با قوانین فعال هم سبز بماند |
| ۱۰ | شبیهسازی داده واقعی بنویسد | rollback در finally + em->clear() + تست شمارش ردیف |
| ۱۱ | quote اعتبار مصرف کند |
مصرف فقط در confirm؛ تست: ده quote → مانده بیتغییر |
| ۱۲ | book-all نیمهکاره |
همه یا هیچ در یک تراکنش |
cross-repo — بررسی دستی اجباری
nobat724_front/services/response.js و clinic-pro-tauri/src/service/response.js هر دو
مصرفکنندهٔ همان /api/v1/... اند. تغییر قرارداد در build هیچکدام خطا نمیدهد و در
runtime میشکند (guidelines §۳).
تسکهایی که قرارداد را واقعاً عوض میکنند و بررسی دستیشان بحرانی است:
- ۰۰ —
service_itemتکی باید باservice_itemsهمگام بماند (چهار مصرفکننده رویش خواندهاند) - ۰۴ — مدت نوبتهای چندسرویسی عوض میشود (فرمول «زمان تنها/زمان اضافه»)
- ۰۶ — پس از ارتقای یک کلینیک به
resource، کلاینت باید مسیر جدید صدا بزند - ۰۸ — مبلغ نمایشی رزرو ممکن است عوض شود
- ۱۳ — سایت باید
cancellation-previewرا نشان دهد
در گزارش هر تسک، فایلهای بررسیشده را نام ببر؛ «بررسی شد» بیارزش است.
وقتی متن تسک با کد واقعی نمیخواند
تسکها از خواندن کد در تاریخ نوشتنشان ساخته شدهاند. اگر جایی متن با کد امروز نخواند:
- کد واقعی مرجع است، نه متن تسک
- اختلاف را به کاربر بگو
- متن تسک را اصلاح کن (فایل تسک هم سند است — guidelines §۴)
- بعد پیادهسازی کن
موارد شناختهشدهای که تسکها خودشان علامت زدهاند و باید پیش از کدنویسی تأیید شوند:
- تسک ۱۴ ردیف ۲.۹ — وجود
patient_sessions.started_at/ended_at؛ اگر نبود، گزارشplan-accuracyبه تسک جدا موکول میشود، نه ساخته شدن با داده حدسی - تسک ۰۰ب بخش ۱ — وجود
service_itemsوservice_total_minutesدر پاسخGET /api/v1/appointments/user؛ اگر نبود، به تسک ۰۰ برمیگردد - تسک ۰۷ database.md — وابستگی معکوس: جدول
resource_occupancyدر تسک ۰۶ migrate میشود، تعریفش در ۰۷ است