- 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.
113 lines
4.8 KiB
Markdown
113 lines
4.8 KiB
Markdown
# دیتابیس — تسک ۰۳
|
||
|
||
## `resource_calendars`
|
||
|
||
شیفت تکرارشوندهٔ هفتگی یک منبع.
|
||
|
||
| ستون | نوع | توضیح |
|
||
|---|---|---|
|
||
| `id` | INT PK AI | |
|
||
| `resource_id` | INT NOT NULL | FK → `clinic_resources.id` ON DELETE CASCADE |
|
||
| `day_of_week` | TINYINT NOT NULL | ۰=شنبه … ۶=جمعه |
|
||
| `sequence` | TINYINT NOT NULL DEFAULT 0 | |
|
||
| `start_minute` | SMALLINT NOT NULL | |
|
||
| `end_minute` | SMALLINT NOT NULL | |
|
||
| `valid_from` | INT NULL | شیفت فصلی؛ NULL = از همیشه |
|
||
| `valid_to` | INT NULL | NULL = تا همیشه |
|
||
| `active` | TINYINT(1) NOT NULL DEFAULT 1 | |
|
||
|
||
```sql
|
||
UNIQUE KEY uniq_rc_resource_day_seq (resource_id, day_of_week, sequence)
|
||
KEY idx_rc_resource_day (resource_id, day_of_week, active)
|
||
```
|
||
|
||
`valid_from/valid_to` از روز اول: شیفت تابستانی/زمستانی حالت رایج کلینیک است و
|
||
افزودنش بعداً یعنی یا حذف و ثبت دوبارهٔ شیفتها یا یک جدول موازی.
|
||
|
||
فرزند aggregate با ریشهٔ `ClinicResource`.
|
||
|
||
## `resource_exceptions`
|
||
|
||
| ستون | نوع | توضیح |
|
||
|---|---|---|
|
||
| `id` | INT PK AI | |
|
||
| `uuid` | VARCHAR(36) UNIQUE | **از request میآید** → جفت tenant خودش را دارد |
|
||
| `entity_type` / `entity_id` | VARCHAR(10) / INT NOT NULL | از منبع مشتق میشود |
|
||
| `resource_id` | INT NOT NULL | FK ON DELETE CASCADE |
|
||
| `type` | VARCHAR(20) NOT NULL | `leave` \| `absence` \| `maintenance` \| `blocked` |
|
||
| `start_at` | INT NOT NULL | Unix |
|
||
| `end_at` | INT NOT NULL | Unix، `> start_at` |
|
||
| `reason` | VARCHAR(255) NULL | |
|
||
| `created_by` | INT NULL | FK → `users.id` ON DELETE SET NULL |
|
||
| `created_at` | INT NOT NULL | |
|
||
|
||
```sql
|
||
KEY idx_rex_tenant (entity_type, entity_id, start_at)
|
||
KEY idx_rex_resource_range (resource_id, start_at, end_at)
|
||
```
|
||
|
||
`idx_rex_resource_range` کوئری داغ است: «استثناهای این منبع که با [from, to) تداخل دارند».
|
||
|
||
> نوع `blocked` عمداً هست: مسدود کردن دستیِ یک بازه توسط منشی («امروز عصر کسی را نگذار»)
|
||
> با مرخصی یکی نیست و گزارش بهرهوری (تسک ۱۴) باید تفکیکشان کند.
|
||
|
||
## `national_holidays`
|
||
|
||
| ستون | نوع | توضیح |
|
||
|---|---|---|
|
||
| `id` | INT PK AI | |
|
||
| `date` | INT NOT NULL UNIQUE | نیمهشب روز به وقت `Asia/Tehran`، Unix |
|
||
| `jalali_date` | VARCHAR(10) NOT NULL | `1405-01-13` — برای import و نمایش |
|
||
| `title` | VARCHAR(150) NOT NULL | |
|
||
| `is_official` | TINYINT(1) NOT NULL DEFAULT 1 | مناسبت غیرتعطیل هم ثبت میشود |
|
||
| `created_at` | INT NOT NULL | |
|
||
|
||
```sql
|
||
UNIQUE KEY uniq_national_holiday_date (date)
|
||
KEY idx_national_holiday_jalali (jalali_date)
|
||
```
|
||
|
||
سراسری — در `GlobalTables::ENTITIES` با دلیل: «تقویم رسمی کشور، مال هیچ محیطی نیست».
|
||
|
||
## `tenant_holiday_overrides`
|
||
|
||
| ستون | نوع | توضیح |
|
||
|---|---|---|
|
||
| `id` | INT PK AI | |
|
||
| `uuid` | VARCHAR(36) UNIQUE | |
|
||
| `entity_type` / `entity_id` | VARCHAR(10) / INT NOT NULL | |
|
||
| `date` | INT NOT NULL | نیمهشب روز |
|
||
| `is_working` | TINYINT(1) NOT NULL | true = روز رسمیِ تعطیل، برای ما کاری است |
|
||
| `note` | VARCHAR(255) NULL | |
|
||
| `created_at` | INT NOT NULL | |
|
||
|
||
```sql
|
||
UNIQUE KEY uniq_tho_tenant_date (entity_type, entity_id, date)
|
||
KEY idx_tho_tenant (entity_type, entity_id, date)
|
||
```
|
||
|
||
`is_working=false` هم معنی دارد: روزی که رسمی نیست ولی این محیط تعطیل است (مثلاً
|
||
تعطیلی سالانهٔ کلینیک). پس این جدول هر دو جهت را میپوشاند و `Holiday` موجود فقط برای
|
||
سازگاری عقبرو در حالت `slot`/`service` میماند.
|
||
|
||
## Migration
|
||
|
||
```bash
|
||
ddev exec php bin/console doctrine:migrations:diff --no-interaction
|
||
ddev exec php bin/console doctrine:migrations:migrate --no-interaction
|
||
ddev exec php bin/console app:holiday:import --year=1405 --file=var/holidays-1405.json
|
||
```
|
||
|
||
`app:resource:calendar:backfill` (اختیاری، در همین تسک): برای هر منبعِ `type=doctor` که از
|
||
`WeeklySchedule` ساخته شده، شیفتهای همان برنامه را به `resource_calendars` کپی میکند تا
|
||
تقویم منبع از روز اول خالی نباشد. dry-run پیشفرض.
|
||
|
||
## طبقهبندی tenant
|
||
|
||
| جدول | وضعیت | دلیل |
|
||
|---|---|---|
|
||
| `resource_calendars` | `AGGREGATE_CHILDREN` | ریشه `ClinicResource`؛ uuid از request نمیگیرد |
|
||
| `resource_exceptions` | جفت tenant | uuid از request میآید (`PATCH /resource-exception/{uuid}`) |
|
||
| `national_holidays` | `ENTITIES` | تقویم کشوری |
|
||
| `tenant_holiday_overrides` | جفت tenant | |
|