- Add implementation notes for cancellation and waitlist features. - Create task documentation outlining goals, current status, and acceptance criteria for cancellation policy and resource utilization reporting. - Establish architecture for domain events and outbox pattern to ensure reliable event publishing. - Define database schema for domain events and necessary queries for resource utilization and plan accuracy reports. - Implement detailed implementation notes covering edge cases, testing strategies, and documentation requirements.
76 lines
4.4 KiB
Markdown
76 lines
4.4 KiB
Markdown
# تسک ۰۲ — مدل منبع: نوع منبع، منبع، مهارت، استخر
|
||
|
||
**فاز:** ۱ (هسته) · **وابستگی:** ۰۱ · **زمان:** ۱۴-۱۸ ساعت
|
||
|
||
---
|
||
|
||
## هدف
|
||
|
||
قانون طلایی اول مستند: «تقویم مال منبع است، نه مال پزشک». امروز تنها موجودیتی که
|
||
میتواند اشغال شود پزشک است و پرسنل (`ClinicStaff`) فقط یک برچسب روی سرویس و نوبت است.
|
||
این تسک لایهٔ منبع را میسازد: هر چیزی که ممکن است اشغال باشد — پزشک، اپراتور، دستیار،
|
||
دستگاه، اتاق، تخت، یونیت.
|
||
|
||
## وضعیت فعلی
|
||
|
||
```php
|
||
// src/Staff/Entity/ClinicStaff.php — تنها «منبع» امروز
|
||
private string $fullName;
|
||
private ?string $jobTitle; // متن آزاد، بدون معنای ساختاری
|
||
private bool $active;
|
||
private ?User $user; // برای ورود به پنل
|
||
```
|
||
|
||
بدون تقویم، بدون ظرفیت، بدون مهارت. `ServiceItem.staffMembers` یک ManyToMany به همین است
|
||
و `Appointment.staff_id` یک ارجاع تکی — هیچکدام تداخل زمانی را بررسی نمیکنند.
|
||
|
||
## دامنه
|
||
|
||
**هست:** `ResourceType`، `Resource`، `Skill`، `ResourceSkill`، `ResourcePool`،
|
||
`ResourcePoolMember`، ویژگیهای آزاد (`attributes` JSON)، ظرفیت همزمان،
|
||
زمان آمادهسازی/تمیزکاری per منبع، CRUD پنل، و **پل زدن `ClinicStaff` و `Doctor` و `Room`
|
||
به `Resource`**.
|
||
|
||
**نیست:** تقویم و مرخصی (تسک ۰۳)، نیازمندی منبع per بخش (تسک ۰۵)، محاسبهٔ اشغال (تسک ۰۶/۰۷).
|
||
|
||
## Endpoint ها
|
||
|
||
| متد | مسیر | توضیح |
|
||
|---|---|---|
|
||
| GET/POST | `/api/v1/resource-types` | نوع منبع (کلینیک خودش تعریف میکند) |
|
||
| PATCH/DELETE | `/api/v1/resource-type/{uuid}` | |
|
||
| GET | `/api/v1/resources` | لیست با فیلتر `branch_uuid`, `type_uuid`, `active` |
|
||
| POST | `/api/v1/resource` | ساخت منبع |
|
||
| GET/PATCH/DELETE | `/api/v1/resource/{uuid}` | |
|
||
| GET/POST | `/api/v1/skills` | مهارتها |
|
||
| PATCH/DELETE | `/api/v1/skill/{uuid}` | |
|
||
| PUT | `/api/v1/resource/{uuid}/skills` | جایگزینی کامل مهارتهای منبع |
|
||
| GET/POST | `/api/v1/resource-pools` | استخر منابع قابل جایگزینی |
|
||
| PATCH/DELETE | `/api/v1/resource-pool/{uuid}` | |
|
||
| PUT | `/api/v1/resource-pool/{uuid}/members` | جایگزینی کامل اعضا |
|
||
|
||
## معیار پذیرش
|
||
|
||
- ✅ موفق: کلینیک نوع منبع «دستگاه لیزر» میسازد، سه منبع از آن نوع در شعبهٔ مرکزی ثبت
|
||
میکند، یک استخر «لیزرهای آلکساندرایت» میسازد و هر سه را عضو میکند →
|
||
`GET /api/v1/resource-pool/{uuid}` هر سه را با `branch_uuid` برمیگرداند.
|
||
- ✅ موفق: مهارت «لیزر آلکساندرایت» ساخته و به دو اپراتور داده میشود →
|
||
`GET /api/v1/resources?skill_uuid=…` فقط همان دو را برمیگرداند.
|
||
- ✅ موفق: بعد از اجرای `app:resource:backfill`، هر `ClinicStaff` فعال یک `Resource` با
|
||
`type=staff` و هر `Doctor` دارای برنامه یک `Resource` با `type=doctor` دارد.
|
||
- ❌ خطا: منبع با `branch_uuid` متعلق به محیط دیگر → `404`.
|
||
- ❌ خطا: عضو کردن منبعی از شعبهٔ A در استخری که منابعش در شعبهٔ B هستند → `422`
|
||
«همهٔ اعضای استخر باید در یک شعبه باشند».
|
||
- ⚠️ مرزی: `capacity = 3` روی اتاق تزریق → یک ردیف، نه سه. `GET` مقدار ۳ را برمیگرداند.
|
||
- ⚠️ مرزی: `setup_minutes = 0, cleanup_minutes = 10` → معتبر.
|
||
- ⚠️ مرزی: حذف مهارتی که به منبعی داده شده → `422`؛ باید اول از منابع برداشته شود.
|
||
- ⚠️ مرزی: `attributes` با کلید ناشناخته → پذیرفته میشود (عمداً آزاد)، ولی مقدار غیر
|
||
اسکالر → `422`.
|
||
|
||
## خروجی
|
||
|
||
- `src/Resource/` کامل با تست
|
||
- صفحات پنل: `ResourcesPage`, `ResourceFormPage`, `ResourceTypesPage`, `SkillsPage`, `ResourcePoolsPage`
|
||
- `docs/api/resource.md`
|
||
- `app:resource:backfill` (dry-run پیشفرض)
|