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

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 اجبار شود؛ MariaDB CHECK چندستونی را قابل اتکا اجرا نمی‌کند.

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 برای هر محیط:

  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