# چک‌لیست — تسک ۰۵ (بخش‌های نوبت و سازندهٔ برنامه)

**وضعیت کلی:** ⏳ شروع نشده · **آخرین بازبینی:** —

قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) ·
[red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md)

---

## ۰. خط سرخ

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۰.۱ | `--group=slot-mode-frozen` سبز | ⏳ | |
| ۰.۲ | `SlotCalculatorService` دست‌نخورده | ⏳ | |
| ۰.۳ | سرویس بدون `SegmentTemplate` → یک بخش مجازی با منبع `type=doctor` | ⏳ | ⭐ سازگاری حالت `service` فعلی |
| ۰.۴ | هیچ جدولی برای «برنامهٔ ساخته‌شده» ساخته نشد | ⏳ | DTO درون‌حافظه؛ ذخیره کار تسک ۰۷ |

## ۱. بک‌اند

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۱.۱ | `SegmentTemplate` · `SegmentRequirement` | ⏳ | |
| ۱.۲ | DTO های `AppointmentPlan` · `PlannedSegment` · `PlannedRequirement` (immutable) | ⏳ | |
| ۱.۳ | پنج سرویس جدا: `Builder` · `Assembler` · `DurationResolver` · `RequirementResolver` | ⏳ | نه یک کلاس بزرگ |
| ۱.۴ | `build()` تابع **خالص** است — بدون write، بدون cache، بدون `time()` | ⏳ | ⭐ تسک ۰۶ رویش حساب می‌کند |
| ۱.۵ | مرحلهٔ ۷ (`policies->applyToPlan`) از روز اول در امضا، حتی no-op | ⏳ | تسک ۰۹ پرش می‌کند |
| ۱.۶ | ادغام: `count` **بیشینه**، نه جمع | ⏳ | |
| ۱.۷ | `offset_minutes` نسبی است، نه timestamp مطلق | ⏳ | تسک ۰۶ برنامه را می‌لغزاند |
| ۱.۸ | `occupancyStartOffset`/`occupancyEndOffset` جدا از offset نمایشی | ⏳ | `setup/cleanup` |
| ۱.۹ | قید جنسیت بدون داده → ۴۲۲، **نه نادیده گرفتن** | ⏳ | ⭐ الزام جدی کلینیک زیبایی |
| ۱.۱۰ | `constraints` فهرست بسته؛ کلید ناشناخته → ۴۲۲ | ⏳ | |
| ۱.۱۱ | `NoEligibleResourceException` با پیام انسانی + `meta` | ⏳ | نقش، مهارت، شعبه |
| ۱.۱۲ | سه endpoint | ⏳ | |
| ۱.۱۳ | `patient_facing_minutes` جدا از `total_minutes` در پاسخ | ⏳ | بخش‌های بدون حضور بیمار |
| ۱.۱۴ | سقف‌ها اعمال شد: ۲۰ بخش · ۴۸۰ دقیقه · ۱۰ نیازمندی · ۲۰ آیتم | ⏳ | |
| ۱.۱۵ | `app:segment:seed-templates --preset=beauty\|dental\|physio` — dry-run | ⏳ | |
| ۱.۱۶ | `TenantOwnershipChecker` روی هر uuid از request | ⏳ | |

## ۲. دیتابیس

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۲.۱ | `segment_templates` · `segment_requirements` | ⏳ | |
| ۲.۲ | دقیقاً یکی از `service_item_id`/`service_option_id` — قید اپلیکیشنی | ⏳ | |
| ۲.۳ | دقیقاً یکی از `fixed_minutes`/`duration_share` | ⏳ | |
| ۲.۴ | جمع `duration_share` یک سرویس = ۱۰۰ (اعتبارسنجی هنگام ذخیره) | ⏳ | |
| ۲.۵ | `required_skills` به‌صورت JSON با دلیل مکتوب | ⏳ | نه جدول واسط |
| ۲.۶ | `segment_requirements` در `AGGREGATE_CHILDREN` | ⏳ | |
| ۲.۷ | `TenantSchemaCoverageTest` سبز | ⏳ | |

## ۳. UI

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۳.۱ | `ServiceSegmentsPage` به‌عنوان زیرصفحهٔ `ServiceDetailPage` | ⏳ | |
| ۳.۲ | لیست بخش‌ها با `sequence` عددی (بدون drag) | ⏳ | |
| ۳.۳ | نیازمندی‌ها: نقش با `SearchableSelect`، مهارت با چیپ، اشغال با رادیو | ⏳ | |
| ۳.۴ | هر گزینهٔ نوع اشغال توضیح فارسی دارد | ⏳ | انحصاری/اشتراکی/منفعل |
| ۳.۵ | **نوار پیش‌نمایش زمانی** با عرض متناسب مدت و آیکن منابع | ⏳ | ⭐ تنها راه فهم کاربر غیرفنی |
| ۳.۶ | خط «اپراتور واقعاً درگیر: N دقیقه» زیر نوار | ⏳ | ⭐ ارزش کار را نشان می‌دهد |
| ۳.۷ | `backTo` روی صفحه | ⏳ | |
| ۳.۸ | هیچ رنگ/شعاع hard-code — نوار پیش‌نمایش هم | ⏳ | |
| ۳.۹ | دارک‌مود و حالت فشرده | ⏳ | |
| ۳.۱۰ | RTL و موبایل — نوار پیش‌نمایش روی موبایل اسکرول افقی داخلی دارد | ⏳ | |
| ۳.۱۱ | همهٔ رشته‌ها فارسی | ⏳ | |
| ۳.۱۲ | `meta` خطای «هیچ منبعی» به لینک «افزودن منبع» تبدیل شد | ⏳ | بن‌بست نباشد |

## ۴. تست

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۴.۱ | `SegmentAssemblerTest` — ادغام، `count` بیشینه، غیر-mergeable | ⏳ | |
| ۴.۲ | `SegmentDurationResolverTest` — fixed ثابت، سهمی مقیاس‌پذیر، جمع = total | ⏳ | |
| ۴.۳ | `AppointmentPlanBuilderTest` — سناریوی کامل مستند (۰/۵/۳۵/۵۵، total=60) | ⏳ | |
| ۴.۴ | `AppointmentPlanBuilderTest` — **قطعیت**: دو build یکسان → خروجی یکسان | ⏳ | |
| ۴.۵ | سرویس بدون الگو → یک بخش با منبع doctor | ⏳ | ⭐ |
| ۴.۶ | `RequirementResolverTest` — مهارت، هیچ کاندید، قید جنسیت، محیط دیگر | ⏳ | |
| ۴.۷ | `PlanLimitsTest` — ۲۱ بخش و ۴۸۱ دقیقه → ۴۲۲ | ⏳ | |

## ۵. مستندات

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۵.۱ | `docs/api/appointment-plan.md` | ⏳ | |
| ۵.۲ | جدول سه حالت اشغال و تفاوت عملی‌شان | ⏳ | |
| ۵.۳ | تفاوت `offset` نمایشی با `occupancy_offset` | ⏳ | |
| ۵.۴ | مثال کامل خروجی `preview` | ⏳ | |

## ۶. بازبینی پایانی

| # | مورد | وضعیت | یادداشت |
|---|---|---|---|
| ۶.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ⏳ | |
| ۶.۲ | `bin/phpunit` کامل سبز | ⏳ | |
| ۶.۳ | `--group=slot-mode-frozen` سبز | ⏳ | |
| ۶.۴ | `phpstan` بدون خطای جدید | ⏳ | |
| ۶.۵ | `npx tsc --noEmit` و `yarn test` سبز | ⏳ | |
| ۶.۶ | تست‌های tenant سبز | ⏳ | |
| ۶.۷ | `docs/api/*` به‌روز | ⏳ | |
| ۶.۸ | چک‌لیست UI کامل | ⏳ | |
| ۶.۹ | دو کلاینت دیگر بررسی شدند | ⏳ | `preview` هنوز مصرف نمی‌شود |
| ۶.۱۰ | commit، سپس `graphify update .` | ⏳ | |
| ۶.۱۱ | موارد به‌تعویق با دلیل و تسک مقصد | ⏳ | |
