Files
clinicpro/.claude/prompt/booking-engine-task-runner.md
T
hamedandClaude Opus 5 c37c0cee39 test(booking): freeze slot-mode contract before service-mode work
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>
2026-07-30 12:31:57 +03:30

570 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# راهبر اجرای تسک‌های موتور نوبت‌دهی — یک تسک در هر اجرا
## پروژه
`clinicpro` (بک‌اند + پنل ادمین)
پرامپت همتا برای سایت عمومی: `nobat724_front/.claude/prompt/booking-engine-task-00b-service-mode.md`
(همین راهبر وقتی به تسک ۰۰ب برسد، تحویلش می‌دهد و می‌ایستد.)
---
## زمینه
`docs/new_feture/taskes/` شانزده تسک برای پیاده‌سازی
[مستند موتور نوبت‌دهی](../../docs/new_feture/clinic-pro-mostanad-sade.md) دارد. هر تسک یک
پوشه با شش فایل است و **خودش یک پرامپت کامل است**: `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` ساخته شده و **همهٔ ردیف‌هایشان `⏳` است**. هیچ تسکی شروع نشده.
ساختار ثابت هر چک‌لیست:
```markdown
# چک‌لیست — تسک 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/`، پنج قاعدهٔ غیرقابل‌مذاکره.
- ☑️ هیچ تسکی بدون تکمیل چک‌لیستش تمام نیست.
**نحوه تست:** بعد از خواندن، در گزارش شروع بنویس کدام سه سند خوانده شد و مهم‌ترین قید
مربوط به تسک انتخاب‌شده چیست (یک جمله).
---
### ۲. شناسایی وضعیت و انتخاب تسک
همهٔ چک‌لیست‌ها را بخوان و وضعیت هر تسک را از **ردیف‌هایش** استنتاج کن، نه از خط
«وضعیت کلی» (که ممکن است به‌روز نشده باشد):
```bash
# فهرست چک‌لیست‌ها به ترتیب
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
```
قاعدهٔ استنتاج:
```
تمام‌شده = هیچ ردیف 🔄 · هیچ ردیف ⚠️ · هیچ ردیف ⏳ بدون یادداشتِ دلیل
در جریان = حداقل یک ردیف 🔄 یا ⚠️
شروع نشده = همهٔ ردیف‌ها ⏳ و هیچ یادداشتی
```
قاعدهٔ انتخاب، به همین ترتیب:
1. اگر تسکی **در جریان** است → همان. (تسک نیمه‌کاره رها نمی‌شود.)
2. وگرنه اولین تسکِ **شروع نشده** که همهٔ وابستگی‌هایش **تمام‌شده** اند.
3. اگر کاربر `--task=XX` داد → همان، ولی وابستگی‌ها همچنان بررسی می‌شوند.
4. اگر همه تمام‌شده‌اند → پیام و توقف.
5. اگر تسک انتخاب‌شده وابستگی ناقص دارد → توقف با نام تسک پیش‌نیاز.
جدول وضعیت را به کاربر نشان بده و تسک انتخاب‌شده را اعلام کن:
```
📊 وضعیت تسک‌ها
۰۰ تکمیل سرویسی ✅ تمام‌شده
۰۰ب سازگارسازی سایت ✅ تمام‌شده
۰۱ شعبه و اتاق 🔄 در جریان (۱۲/۳۸)
۰۲ منبع و مهارت ⏳ شروع نشده
🎯 تسک انتخاب‌شده: ۰۱ — شعبه و اتاق (ادامهٔ کار نیمه‌کاره)
```
**نحوه تست:** دستور شمارش بالا را اجرا کن و خروجی واقعی‌اش را در گزارش بگذار. جدول
نمایش‌داده‌شده باید با آن خروجی بخواند.
---
### ۳. تحویل به پرامپت همتا اگر تسک ۰۰ب انتخاب شد
تسک ۰۰ب روی `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` **اضافه
کن** و به کاربر بگو. انجام بی‌صدا ممنوع.
**نحوه تست:** دستورهای هر پروژه بعد از هر ردیفِ منطق‌دار:
```bash
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`
چک‌لیست **حافظهٔ بین‌اجرایی** است. اگر به‌روز نشود، اجرای بعدی کار انجام‌شده را دوباره
انجام می‌دهد.
قواعد نوشتن:
- ردیف را **همان لحظه** که شروع می‌کنی `⏳ → 🔄` کن، نه در پایان تسک
- تمام شد → `🔄 → ✅` با یادداشت کوتاه اگر چیزی برای گفتن هست (مسیر فایل، عدد اندازه‌گیری‌شده)
- شکست خورد یا بلاک شد → `⚠️` با **دلیل** در ستون یادداشت
- به تعویق افتاد → `⏳` با **دلیل + تسک مقصد** در یادداشت. `⏳` بی‌دلیل = تسک تمام نشده.
- خط سربرگ را هم به‌روز کن:
```markdown
**وضعیت کلی:** 🔄 در حال انجام · **آخرین بازبینی:** ۱۴۰۵/۰۵/۰۳
```
پیش از رفتن به وظیفهٔ ۶، **بخش ۶ (یا ۷/۸ بسته به تسک) بازبینی پایانی** را ردیف‌به‌ردیف
اجرا کن. ردیف‌های مشترک همهٔ تسک‌ها:
```
همهٔ ردیف‌های بالا وضعیت نهایی دارند (هیچ 🔄 و ⏳ بی‌دلیل)
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` — وگرنه گراف وضعیت کامیت‌نشده را
ایندکس می‌کند.
```bash
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` هستی، **اول برنچ بساز**:
```bash
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` کامل است. پنج قاعده‌ای که رعایت نکردنشان یعنی رد شدن ردیف:
1. `SearchableSelect`، هرگز `<select>` بومی
2. زیرصفحه‌ها `backTo` یا `<BackButton fallback="…" />` — دکمهٔ دست‌ساز نه
3. وضعیت لیست (جستجو/فیلتر/صفحه) در URL با `hooks/useUrlState.ts`، نه `useState`
4. داده فقط TanStack Query از `lib/api.ts`؛ استخراج: paginated → `data?.data` +
`data?.meta?.totalRecords` · single → `data?.data` · Category → `data?.data?.data ?? []`
5. فرم با 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` را نشان دهد
در گزارش هر تسک، **فایل‌های بررسی‌شده را نام ببر**؛ «بررسی شد» بی‌ارزش است.
### وقتی متن تسک با کد واقعی نمی‌خواند
تسک‌ها از خواندن کد در تاریخ نوشتنشان ساخته شده‌اند. اگر جایی متن با کد امروز نخواند:
1. **کد واقعی مرجع است**، نه متن تسک
2. اختلاف را به کاربر بگو
3. متن تسک را اصلاح کن (فایل تسک هم سند است — guidelines §۴)
4. بعد پیاده‌سازی کن
موارد شناخته‌شده‌ای که تسک‌ها خودشان علامت زده‌اند و باید **پیش از کدنویسی** تأیید شوند:
- تسک ۱۴ ردیف ۲.۹ — وجود `patient_sessions.started_at/ended_at`؛ اگر نبود، گزارش
`plan-accuracy` به تسک جدا موکول می‌شود، **نه** ساخته شدن با داده حدسی
- تسک ۰۰ب بخش ۱ — وجود `service_items` و `service_total_minutes` در پاسخ
`GET /api/v1/appointments/user`؛ اگر نبود، به تسک ۰۰ برمی‌گردد
- تسک ۰۷ database.md — وابستگی معکوس: جدول `resource_occupancy` در تسک **۰۶** migrate
می‌شود، تعریفش در ۰۷ است