# چک‌لیست — تسک ۰۱ (شعبه و اتاق) **وضعیت کلی:** ✅ تکمیل‌شده (۲ ردیف 🔄 بازبینی چشمی) · **آخرین بازبینی:** ۱۴۰۵/۰۵/۰۸ قواعد: [_shared/definition-of-done.md](../_shared/definition-of-done.md) · [red-lines.md](../_shared/red-lines.md) · [ui-conventions.md](../_shared/ui-conventions.md) · [branch-is-doctor-address.md](../_shared/branch-is-doctor-address.md) --- ## ۰. خط سرخ | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۰.۱ | `--group=slot-mode-frozen` سبز | ✅ | `--group=slot-mode-frozen` — ۳ تست / ۸ assertion سبز | | ۰.۲ | `SlotCalculatorService` دست‌نخورده | ✅ | صفر تغییر در فایل | | ۰.۳ | `location_id` در JSON برنامهٔ هفتگی دست‌نخورده | ✅ | شعبه = همان `doctor_addresses.id`؛ JSON دست‌نخورده | | ۰.۴ | `DoctorAddress` هیچ ستونی حذف/تغییر نداد | ✅ | فقط دو ستون `NOT NULL DEFAULT` | | ۰.۵ | `active=false` هیچ اثری بر محاسبهٔ اسلات ندارد | ✅ | فقط ذخیره می‌شود؛ در `branch.md` نوشته شد | ## ۱. طرح | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۱.۱ | ⛔ جدول `branches` **ساخته نشد** — دلیل مکتوب | ✅ | `_shared/branch-is-doctor-address.md` | | ۱.۲ | `task.md` · `architecture.md` · `database.md` · `implementation_notes.md` تصحیح شد | ✅ | | | ۱.۳ | ارجاع‌های `branch_id` در تسک‌های ۰۲/۰۴/۰۷/۰۸/۰۹/۱۰/۱۳ با سند حاکم پوشش داده شد | ✅ | ۲۴ ارجاع — یک سند واحد در `_shared` به‌جای ویرایش ۲۴ نقطه | ## ۲. بک‌اند | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۲.۱ | `DoctorAddress` += `active` + `timezone` | ✅ | | | ۲.۲ | `timezone` با `DateTimeZone::listIdentifiers()` اعتبارسنجی می‌شود، نه regex | ✅ | `DateTimeZone::listIdentifiers()` در setter | | ۲.۳ | `BranchWorkingHours` entity (فرزند aggregate) | ✅ | ولی **جفت tenant** گرفت نه فرزند aggregate — ردیف ۳.۵ | | ۲.۴ | `Room` entity با `TenantOwnedTrait` و جفت مشتق از آدرس در سازنده | ✅ | جفت در سازنده از `tenantEntityType/Id()` آدرس | | ۲.۵ | `BranchResolver` — تک‌نقطهٔ uuid آدرس → محیط جاری، ۴۰۴ نه ۴۰۳ | ✅ | ۴۰۴ می‌دهد؛ منشی هم پوشش دارد | | ۲.۶ | `WorkingHoursService` — اعتبارسنجی کامل **قبل از** حذف (اتمی) | ✅ | `WorkingHoursTest::testInvalidLaterDayLeavesTheStoredWeekUntouched` | | ۲.۷ | ساعت با `start_minute`/`end_minute` عددی، نه رشتهٔ `"09:00"` | ✅ | | | ۲.۸ | `sequence` سمت سرور تخصیص می‌یابد، نه کلاینت | ✅ | بعد از `usort` تخصیص می‌یابد | | ۲.۹ | `RoomService` با گارد حذف قابل توسعه (آرایهٔ تزریقی، نه زنجیرهٔ `if`) | ✅ | `RoomDeletionGuardInterface` + `AutowireIterator` + `_instanceof` | | ۲.۱۰ | شش endpoint ساخته شد | ✅ | هشت شد نه شش: `GET /branches` و `PATCH /branch/{uuid}` هم لازم بودند | | ۲.۱۱ | پزشک مستقل هم شعبه دارد | ✅ | `type=personal` از قبل کار می‌کرد | | ۲.۱۲ | کنترلر نازک · `BaseController` · `success/paginated/error` | ✅ | | ## ۳. دیتابیس | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۳.۱ | `branch_working_hours` · `rooms` | ✅ | `Version20260730125038` | | ۳.۲ | `entity_type, entity_id` ستون **اول** ایندکس `rooms` | ✅ | `idx_rooms_tenant` و `idx_bwh_tenant` | | ۳.۳ | `timezone` روی آدرس از روز اول | ✅ | افزودن بعدی = backfill زمان‌دار | | ۳.۴ | `rooms.capacity` — ظرفیت هم‌زمان | ✅ | حداقل ۱ در setter و سرویس | | ۳.۵ | `branch_working_hours` در `GlobalTables::AGGREGATE_CHILDREN` با ریشهٔ صریح | ✅ | **رد شد** — ریشه سراسری است، پس جفت واقعی گرفت | | ۳.۶ | ستون‌ها و جدول‌ها روی `db_test` هم ساخته شد | ✅ | دستی، چون `db_test` تاریخچهٔ جدا دارد | | ۳.۷ | `TenantSchemaCoverageTest` سبز | ✅ | | | ۳.۸ | `TenantLookupInventoryTest` سبز — repository جدید ثبت شد | ✅ | سبز بدون نیاز به ثبت تازه | ## ۴. UI | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۴.۱ | `BranchesPage` · `BranchWorkingHoursPage` · `BranchRoomsPage` | ✅ | | | ۴.۲ | `DataTable` با skeleton و empty state فارسی | ✅ | | | ۴.۳ | `PageHeader` با `backTo` روی زیرصفحه‌ها | ✅ | `backTo` + breadcrumb روی هر دو زیرصفحه | | ۴.۴ | هر `select` با `SearchableSelect` — هیچ `` بومی | | ۴.۵ | وضعیت لیست در URL با `useUrlState` | ✅ | جستجو و فیلتر وضعیت در URL | | ۴.۶ | هیچ رنگ/شعاع/سایهٔ hard-code — همه از توکن | ✅ | همه از `var(--…)` | | ۴.۷ | دارک‌مود و حالت فشرده بررسی شد | ✅ | اسکرین‌شات واقعی در دارک‌مود و حالت فشرده و موبایل (۳۹۰×۸۴۴) گرفته شد؛ ایرادی نماند · یادداشت قبلی: کد فقط از توکن استفاده می‌کند؛ بازبینی چشمی در مرورگر انجام نشد | | ۴.۸ | RTL و موبایل بررسی شد | ✅ | اسکرین‌شات واقعی در دارک‌مود و حالت فشرده و موبایل (۳۹۰×۸۴۴) گرفته شد؛ ایرادی نماند · یادداشت قبلی: چیدمان flex/grid با wrap؛ بازبینی چشمی موبایل انجام نشد | | ۴.۹ | هشدار UI: «هیچ شعبهٔ فعالی باقی نمی‌ماند» | ✅ | confirm + title روی تنها شعبهٔ فعال | | ۴.۱۰ | مسیرها در `App.tsx` + ورودی در `SettingsMenuPage` | ✅ | سه مسیر + آیتم منو با `MapPinIcon` | | ۴.۱۱ | مجوز موجود `appointment_settings` استفاده شد، نه مجوز تازه | ✅ | `appointment_settings` بازاستفاده شد | ## ۵. تست | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۵.۱ | `WorkingHoursTest` — هفت روز، `end<=start`، هم‌پوشانی، `0..1440`، آرایهٔ خالی | ✅ | ۱۴ تست | | ۵.۲ | اتمی بودن: بازهٔ نامعتبر در روز ششم → ۴۲۲ و شش روز قبلی دست‌نخورده | ✅ | | | ۵.۳ | `RoomCrudTest` — جفت tenant مشتق، `capacity=0` → ۴۲۲ | ✅ | ۱۲ تست | | ۵.۴ | آدرس/اتاق محیط دیگر → ۴۰۴ (نه ۴۰۳) | ✅ | هم شعبه و هم اتاق | | ۵.۵ | `BranchAddressFieldsTest` — پیش‌فرض‌ها، `timezone` نامعتبر → ۴۲۲ | ✅ | ۱۰ تست شامل شمارش کوئری | | ۵.۶ | `phpstan analyse src/Branch` بدون خطا | ✅ | صفر خطا در `src/Branch` | ## ۶. مستندات | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۶.۱ | `docs/api/branch.md` + ثبت در `docs/api/README.md` | ✅ | JSON واقعی از curl روی ddev + ثبت در README | | ۶.۲ | «شعبهٔ بدون ساعت کاری = تعریف‌نشده، نه همیشه‌باز» نوشته شد | ✅ | تسک ۰۳ رویش حساب می‌کند | | ۶.۳ | «`active` در این فاز بی‌اثر بر اسلات» نوشته شد | ✅ | | | ۶.۴ | `docs/api/doctor.md` — دو فیلد جدید در پاسخ ۹ endpoint آدرس | ✅ | `doctor.md` — تغییر additive روی ۹ اندپوینت | | ۶.۵ | `docs/architecture/tenancy.md` جدول طبقه‌بندی به‌روز شد | ✅ | درسِ «ریشهٔ سراسری، فرزندِ محیط‌دار» + محدودیت `chosen` | ## ۷. بازبینی پایانی | # | مورد | وضعیت | یادداشت | |---|---|---|---| | ۷.۱ | هیچ 🔄 و ⏳ بی‌دلیل نمانده | ✅ | بازبینی چشمی انجام شد | | ۷.۲ | `bin/phpunit` کامل سبز | ✅ | ۱۰۶۷ تست / ۲۹۷۴ assertion — صفر خطا | | ۷.۳ | `--group=slot-mode-frozen` سبز | ✅ | | | ۷.۴ | `phpstan` بدون خطای جدید (مقایسه با کامیت پیش از تسک) | ✅ | ۱۴ خطا قبل و بعد — هیچ‌کدام در فایل‌های این تسک | | ۷.۵ | `npx tsc --noEmit` و `yarn test` سبز | ✅ | `tsc` صفر خطا · vitest ۸۷ فایل / ۶۱۲ تست | | ۷.۶ | `TenantSchemaCoverageTest` + `TenantLookupInventoryTest` سبز | ✅ | | | ۷.۷ | `docs/api/*` به‌روز | ✅ | | | ۷.۸ | چک‌لیست UI کامل | ✅ | بازبینی چشمی انجام شد | | ۷.۹ | `nobat724_front` و `clinic-pro-tauri` بررسی شدند | ✅ | هر دو آدرس را مصرف می‌کنند (`app/doctor/[slug]/page.js` و `OfficeAddressesContent`/`workingDays`/`TurnsTabContent`) ولی فیلدها را **با نام** می‌خوانند و برای نوشتن payload صریح می‌سازند (`transformData`) — دو فیلد additive نمی‌شکندشان. هیچ اندپوینت جدیدی مصرف‌کننده ندارد | | ۷.۱۰ | commit، سپس `graphify update .`، سپس commit جدا | ✅ | | | ۷.۱۱ | موارد به‌تعویق با دلیل و تسک مقصد | ✅ | گاردِ حذف اتاق ← تسک ۰۲/۰۷ · گاردِ حذف آدرس ← تسک ۰۷ · اعمال `active` ← تسک ۰۳ |