Files
clinicpro/docs/new_feture/taskes/task-01-branch-room/checklist.md
T
hamedandClaude Opus 5 eebb363b9f feat(branch): branch working hours and rooms on the existing address entity
Task 01 planned a new `branches` table with `doctor_addresses.branch_id` bridging
to it. That plan was wrong: the branch already exists and is called
`DoctorAddress`. It carries name, address, telephone, coordinates, city/province
FKs and an owner (`forDoctor` / `forClinic` + `type`), and the whole system
already consumes it with exactly that meaning — `WeeklySchedule.sessions[].location_id`
points at `doctor_addresses.id`, `appointment-booking-locations` calls each row a
booking location, and nine CRUD endpoints plus four admin pages manage them.
A parallel table would mean two sources of truth for one physical place and a
branch that `location_id` never references.

So no `branches` table and no duplicate branch CRUD. Only the three genuinely
missing pieces:

- `doctor_addresses.active` / `.timezone`, both NOT NULL with a default so
  existing rows need no backfill and no current behaviour changes. `active` is
  stored only — applying it to slot calculation is task 03, since touching
  `SlotCalculatorService` is off limits in this phase.
- `branch_working_hours`, keyed to `doctor_addresses.id`. Minutes from midnight
  rather than "09:00" strings so range intersection stays arithmetic. PUT
  replaces all seven days; validation of the whole week runs before any DELETE,
  so an invalid sixth day cannot wipe the five valid ones and then answer 422.
- `rooms`, with `capacity` as concurrency (a three-bed injection room is one
  resource with capacity 3, not three resources) and a deletion-guard iterator
  so tasks 02 and 07 can add reasons without editing RoomService.

`BranchWorkingHours` first registered as an aggregate child of `DoctorAddress`;
TenantSchemaCoverageTest rejected it correctly, because that root is itself
declared global. It now carries a real tenant pair instead, derived in the
constructor from the address's `type` — a total mapping, and the address is only
ever listed in its own context, so nothing is hidden wrongly.

RoomController checks ownership explicitly rather than trusting TenantFilter:
hard isolation only applies to a *chosen* context, so a doctor who had not
selected one could PATCH another clinic's room. Caught by
RoomCrudTest::testForeignRoomIsNotFound, which failed with 200 before the fix.

35 tests, 97 assertions. Slot-mode frozen contract still green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 16:28:04 +03:30

7.0 KiB
Raw Blame History

چک‌لیست — تسک ۰۱ (شعبه و اتاق)

وضعیت کلی: 🔄 در حال انجام · آخرین بازبینی:

قواعد: _shared/definition-of-done.md · red-lines.md · ui-conventions.md · branch-is-doctor-address.md


۰. خط سرخ

# مورد وضعیت یادداشت
۰.۱ --group=slot-mode-frozen سبز
۰ SlotCalculatorService دست‌نخورده این تسک به آن کاری ندارد
۰ location_id در JSON برنامهٔ هفتگی دست‌نخورده شعبه = همان doctor_addresses.id
۰ DoctorAddress هیچ ستونی حذف/تغییر نداد فقط active و timezone با DEFAULT
۰.۵ active=false هیچ اثری بر محاسبهٔ اسلات ندارد اعمالش تسک ۰۳ است

۱. طرح

# مورد وضعیت یادداشت
۱.۱ جدول 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
۲.۳ BranchWorkingHours entity (فرزند aggregate)
۲.۴ Room entity با TenantOwnedTrait و جفت مشتق از آدرس در سازنده نه از بدنهٔ request
۲.۵ BranchResolver — تک‌نقطهٔ uuid آدرس → محیط جاری، ۴۰۴ نه ۴۰۳ TenantFilter روی doctor_addresses کار نمی‌کند
۲.۶ WorkingHoursService — اعتبارسنجی کامل قبل از حذف (اتمی)
۲.۷ ساعت با start_minute/end_minute عددی، نه رشتهٔ "09:00"
۲.۸ sequence سمت سرور تخصیص می‌یابد، نه کلاینت
۲.۹ RoomService با گارد حذف قابل توسعه (آرایهٔ تزریقی، نه زنجیرهٔ if) تسک ۰۲ و ۰۷ گارد اضافه می‌کنند
۲.۱۰ شش endpoint ساخته شد صفر endpoint CRUD شعبه — موجود است
۲.۱۱ پزشک مستقل هم شعبه دارد type='personal' از قبل کار می‌کند
۲.۱۲ کنترلر نازک · BaseController · success/paginated/error

۳. دیتابیس

# مورد وضعیت یادداشت
۳.۱ branch_working_hours · rooms
۳.۲ entity_type, entity_id ستون اول ایندکس rooms
۳.۳ timezone روی آدرس از روز اول افزودن بعدی = backfill زمان‌دار
۳.۴ rooms.capacity — ظرفیت هم‌زمان اتاق سه‌تخته = یک ردیف با ۳
۳.۵ branch_working_hours در GlobalTables::AGGREGATE_CHILDREN با ریشهٔ صریح
۳.۶ ستون‌ها و جدول‌ها روی db_test هم ساخته شد تاریخچهٔ migration جدا
۳.۷ TenantSchemaCoverageTest سبز
۳.۸ TenantLookupInventoryTest سبز — repository جدید ثبت شد

۴. UI

# مورد وضعیت یادداشت
۴.۱ BranchesPage · BranchWorkingHoursPage · BranchRoomsPage
۴.۲ DataTable با skeleton و empty state فارسی
۴.۳ PageHeader با backTo روی زیرصفحه‌ها
۴.۴ هر select با SearchableSelect — هیچ <select> بومی
۴.۵ وضعیت لیست در URL با useUrlState
۴.۶ هیچ رنگ/شعاع/سایهٔ hard-code — همه از توکن
۴.۷ دارک‌مود و حالت فشرده بررسی شد
۴.۸ RTL و موبایل بررسی شد
۴.۹ هشدار UI: «هیچ شعبهٔ فعالی باقی نمی‌ماند»
۴.۱۰ مسیرها در App.tsx + ورودی در SettingsMenuPage
۴.۱۱ مجوز موجود appointment_settings استفاده شد، نه مجوز تازه

۵. تست

# مورد وضعیت یادداشت
۵.۱ WorkingHoursTest — هفت روز، end<=start، هم‌پوشانی، 0..1440، آرایهٔ خالی
۵ اتمی بودن: بازهٔ نامعتبر در روز ششم → ۴۲۲ و شش روز قبلی دست‌نخورده
۵ RoomCrudTest — جفت tenant مشتق، capacity=0 → ۴۲۲
۵ آدرس/اتاق محیط دیگر → ۴۰۴ (نه ۴۰۳)
۵.۵ BranchAddressFieldsTest — پیش‌فرض‌ها، timezone نامعتبر → ۴۲۲
۵ phpstan analyse src/Branch بدون خطا

۶. مستندات

# مورد وضعیت یادداشت
۶.۱ docs/api/branch.md + ثبت در docs/api/README.md JSON واقعی از curl
۶.۲ «شعبهٔ بدون ساعت کاری = تعریف‌نشده، نه همیشه‌باز» نوشته شد تسک ۰۳ رویش حساب می‌کند
۶.۳ «active در این فاز بی‌اثر بر اسلات» نوشته شد
۶.۴ docs/api/doctor.md — دو فیلد جدید در پاسخ ۹ endpoint آدرس تغییر قرارداد است
۶.۵ docs/architecture/tenancy.md جدول طبقه‌بندی به‌روز شد

۷. بازبینی پایانی

# مورد وضعیت یادداشت
۷.۱ هیچ 🔄 و بی‌دلیل نمانده
۷ bin/phpunit کامل سبز
۷ --group=slot-mode-frozen سبز
۷ phpstan بدون خطای جدید (مقایسه با کامیت پیش از تسک)
۷.۵ npx tsc --noEmit و yarn test سبز
۷ TenantSchemaCoverageTest + TenantLookupInventoryTest سبز
۷.۷ docs/api/* به‌روز
۷ چک‌لیست UI کامل
۷ nobat724_front و clinic-pro-tauri بررسی شدند دو فیلد جدید additive است
۷.۱۰ commit، سپس graphify update .، سپس commit جدا
۷.۱۱ موارد به‌تعویق با دلیل و تسک مقصد