Files
clinicpro/docs/new_feture/taskes/task-02-resource-model/database.md
T
hamed 021d0eb6b2 feat: implement cancellation policy, no-show tracking, and waitlist management
- 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.
2026-07-30 11:43:58 +03:30

144 lines
6.1 KiB
Markdown

# دیتابیس — تسک ۰۲
## `resource_types`
| ستون | نوع | توضیح |
|---|---|---|
| `id` | INT PK AI | |
| `uuid` | VARCHAR(36) UNIQUE | |
| `entity_type` / `entity_id` | VARCHAR(10) / INT NOT NULL | |
| `code` | VARCHAR(40) NOT NULL | `doctor`, `staff`, `room`, `device`, … |
| `name` | VARCHAR(100) NOT NULL | نام نمایشی فارسی |
| `is_system` | TINYINT(1) NOT NULL DEFAULT 0 | نوع‌های `doctor/staff/room` توسط backfill ساخته می‌شوند و حذف نمی‌شوند |
| `active` | TINYINT(1) NOT NULL DEFAULT 1 | |
| `created_at`/`updated_at` | INT NOT NULL | |
```sql
KEY idx_resource_types_tenant (entity_type, entity_id, active)
UNIQUE KEY uniq_rt_tenant_code (entity_type, entity_id, code)
```
## `clinic_resources`
| ستون | نوع | توضیح |
|---|---|---|
| `id` | INT PK AI | |
| `uuid` | VARCHAR(36) UNIQUE | |
| `entity_type` / `entity_id` | VARCHAR(10) / INT NOT NULL | از `branch` مشتق می‌شود |
| `branch_id` | INT NOT NULL | FK → `branches.id` ON DELETE RESTRICT |
| `resource_type_id` | INT NOT NULL | FK → `resource_types.id` ON DELETE RESTRICT |
| `name` | VARCHAR(150) NOT NULL | |
| `capacity` | SMALLINT NOT NULL DEFAULT 1 | ظرفیت هم‌زمان |
| `setup_minutes` | SMALLINT NOT NULL DEFAULT 0 | آماده‌سازی پیش از بیمار |
| `cleanup_minutes` | SMALLINT NOT NULL DEFAULT 0 | تمیزکاری پس از بیمار |
| `attributes` | JSON NULL | اسکالر فقط، حداکثر ۲۰ کلید |
| `doctor_id` | INT NULL UNIQUE | FK → `doctors.id` ON DELETE CASCADE |
| `staff_id` | INT NULL UNIQUE | FK → `clinic_staff.id` ON DELETE CASCADE |
| `room_id` | INT NULL UNIQUE | FK → `rooms.id` ON DELETE CASCADE |
| `active` | TINYINT(1) NOT NULL DEFAULT 1 | |
| `created_at`/`updated_at` | INT NOT NULL | |
```sql
KEY idx_resources_tenant (entity_type, entity_id, active)
KEY idx_resources_branch_type (branch_id, resource_type_id, active)
UNIQUE KEY uniq_resource_doctor (doctor_id)
UNIQUE KEY uniq_resource_staff (staff_id)
UNIQUE KEY uniq_resource_room (room_id)
```
سه کلید یکتای تهی‌پذیر تضمین می‌کنند یک پزشک/پرسنل/اتاق بیش از یک منبع نگیرد.
MariaDB چند `NULL` را در UNIQUE می‌پذیرد، پس دستگاه‌های بدون پل مشکلی ندارند.
> **قید سطح اپلیکیشن (نه DB):** حداکثر یکی از `doctor_id`/`staff_id`/`room_id` غیر-NULL.
> در سازندهٔ entity اجبار شود؛ MariaDB `CHECK` چندستونی را قابل اتکا اجرا نمی‌کند.
## `skills` و `resource_skills`
```sql
CREATE TABLE skills (
id INT PRIMARY KEY AUTO_INCREMENT,
uuid VARCHAR(36) NOT NULL UNIQUE,
entity_type VARCHAR(10) NOT NULL,
entity_id INT NOT NULL,
name VARCHAR(120) NOT NULL,
active TINYINT(1) NOT NULL DEFAULT 1,
created_at INT NOT NULL,
updated_at INT NOT NULL,
KEY idx_skills_tenant (entity_type, entity_id, active)
);
CREATE TABLE resource_skills (
id INT PRIMARY KEY AUTO_INCREMENT,
resource_id INT NOT NULL,
skill_id INT NOT NULL,
level TINYINT NOT NULL DEFAULT 1, -- 1..5
created_at INT NOT NULL,
UNIQUE KEY uniq_resource_skill (resource_id, skill_id),
KEY idx_resource_skills_skill (skill_id, level),
CONSTRAINT fk_rs_resource FOREIGN KEY (resource_id) REFERENCES clinic_resources(id) ON DELETE CASCADE,
CONSTRAINT fk_rs_skill FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE RESTRICT
);
```
`idx_resource_skills_skill (skill_id, level)` عمدی است: پرس‌وجوی داغِ تسک ۰۶
«کدام منابع مهارت X را دارند» از این سمت می‌آید.
`resource_skills` بدون ستون tenant — فرزند aggregate با ریشهٔ `ClinicResource`،
و uuid از request نمی‌گیرد (همیشه از `/resource/{uuid}/skills`).
## `resource_pools` و `resource_pool_members`
```sql
CREATE TABLE resource_pools (
id INT PRIMARY KEY AUTO_INCREMENT,
uuid VARCHAR(36) NOT NULL UNIQUE,
entity_type VARCHAR(10) NOT NULL,
entity_id INT NOT NULL,
branch_id INT NOT NULL,
resource_type_id INT NOT NULL,
name VARCHAR(150) NOT NULL,
active TINYINT(1) NOT NULL DEFAULT 1,
created_at INT NOT NULL,
updated_at INT NOT NULL,
KEY idx_pools_tenant (entity_type, entity_id, active),
KEY idx_pools_branch (branch_id, resource_type_id),
CONSTRAINT fk_pool_branch FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE,
CONSTRAINT fk_pool_type FOREIGN KEY (resource_type_id) REFERENCES resource_types(id) ON DELETE RESTRICT
);
CREATE TABLE resource_pool_members (
id INT PRIMARY KEY AUTO_INCREMENT,
pool_id INT NOT NULL,
resource_id INT NOT NULL,
priority SMALLINT NOT NULL DEFAULT 0, -- ترتیب ترجیح در استراتژی انتخاب
UNIQUE KEY uniq_pool_resource (pool_id, resource_id),
KEY idx_pool_members_resource (resource_id),
CONSTRAINT fk_pm_pool FOREIGN KEY (pool_id) REFERENCES resource_pools(id) ON DELETE CASCADE,
CONSTRAINT fk_pm_resource FOREIGN KEY (resource_id) REFERENCES clinic_resources(id) ON DELETE CASCADE
);
```
## Migration و backfill
```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:resource:backfill # dry-run
ddev exec php bin/console app:resource:backfill --force
```
`app:resource:backfill` برای هر محیط:
1. سه `resource_type` سیستمی می‌سازد (`doctor`, `staff`, `room`) اگر نباشند
2. هر `Room` فعال → یک منبع با `capacity` همان اتاق
3. هر `ClinicStaff` فعال → یک منبع `type=staff` در شعبهٔ اول محیط
4. هر `Doctor` دارای `WeeklySchedule` در آن محیط → یک منبع `type=doctor`
idempotent باشد: اجرای دوباره چیزی دوباره نمی‌سازد.
## طبقه‌بندی tenant
| جدول | وضعیت |
|---|---|
| `resource_types`, `clinic_resources`, `skills`, `resource_pools` | جفت tenant |
| `resource_skills`, `resource_pool_members` | `AGGREGATE_CHILDREN` |