- 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.
6.1 KiB
6.1 KiB
دیتابیس — تسک ۰۲
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 |
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 |
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 اجبار شود؛ MariaDBCHECKچندستونی را قابل اتکا اجرا نمیکند.
skills و resource_skills
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
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
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 برای هر محیط:
- سه
resource_typeسیستمی میسازد (doctor,staff,room) اگر نباشند - هر
Roomفعال → یک منبع باcapacityهمان اتاق - هر
ClinicStaffفعال → یک منبعtype=staffدر شعبهٔ اول محیط - هر
DoctorدارایWeeklyScheduleدر آن محیط → یک منبعtype=doctor
idempotent باشد: اجرای دوباره چیزی دوباره نمیسازد.
طبقهبندی tenant
| جدول | وضعیت |
|---|---|
resource_types, clinic_resources, skills, resource_pools |
جفت tenant |
resource_skills, resource_pool_members |
AGGREGATE_CHILDREN |