Files
clinicpro/.claude/prompt/seed-realistic-data.md
T
hamed df7a784701 feat: implement realistic data seeding for doctors, clinics, and secretaries
- Added seed_realistic_data.php to clean existing data and populate the database with realistic entries for doctors, clinics, and secretaries.
- Created a structured approach to generate 100 doctors per city with diverse specialties and services.
- Implemented database cleanup routines to ensure a fresh start for data seeding.
- Enhanced the DoctorSecretaryRepository with improved comments for clarity.
2026-06-15 14:18:25 +03:30

14 KiB
Raw Blame History

Seed واقعی دیتا — پاک‌سازی و ایجاد ۱۰۰ دکتر به ازای هر شهر

زمینه

پروژه ClinicPro نیاز به دیتای واقعی و کامل برای تست و نمایش دارد. در حال حاضر دیتا ناقص یا تست‌نشده است. باید دیتابیس از دکتر، کلینیک، منشی و بیمار پاک شود، سپس دیتای واقعی با پروفایل کامل ایجاد شود.

هدف

۱. پاک‌سازی کامل: users، doctors، clinics، patient_records، doctor_secretaries ۲. ایجاد یک کلینیک نمونه کامل با همه فیلدها ۳. ایجاد یک دکتر نمونه کامل با برنامه کاری و منشی ۴. ایجاد ۱۰۰ دکتر به ازای هر شهر در تخصص‌های مختلف

ساختار دیتابیس (جداول واقعی)

users              → id, uuid, mobile_number, password_hash, real_name, roles JSON, status
doctors            → id, uuid, user_id, name, gender, medical_system_code, mobile_number, activity_time, degree, info, doctor_rate, doctor_rate_percentage, active_doctor_appointment, representation_id
clinics            → id, uuid, user_id, name, info, address, telephone, is_24_7, working_days, latitude, longitude, city_id, province_id, representation_id, is_active
doctor_addresses   → id, uuid, doctor_id, clinic_id, city_id, province_id, type('personal'|'clinic'), name, address, telephone
weekly_schedules   → id, uuid, doctor_id, setting (JSON — آرایه ۷ روز)
doctor_specialties → doctor_id, specialty_id
doctor_expertise   → doctor_id, service_id
doctor_insurances  → doctor_id, insurance_id
doctor_cities      → doctor_id, city_id
doctor_provinces   → doctor_id, province_id
clinic_doctors     → clinic_id, doctor_id
clinic_specialties → clinic_id, specialty_id
clinic_services    → clinic_id, service_id
clinic_insurances  → clinic_id, insurance_id
doctor_secretaries → id, uuid, doctor_id, secretary_id, active, owner_type, clinic_id
patient_records    → id, uuid, user_id, entity_type, entity_id, created_by_type, created_by_id

IDهای واقعی lookup tables

شهرها (cities.id)

101=تبریز  102=ارومیه  103=اردبیل  104=اصفهان  105=کرج
106=ایلام  107=بوشهر   108=تهران   109=شهرکرد  110=بیرجند
111=مشهد   112=بجنورد  113=اهواز   114=زنجان   115=سمنان
116=زاهدان 117=شیراز   118=قزوین   119=قم      120=سنندج
121=کرمان  122=کرمانشاه 123=یاسوج  125=گرگان   126=رشت
127=خرم‌آباد 128=ساری  129=اراک   130=بندرعباس 131=همدان  132=یزد

استان‌ها (provinces.id)

1=آذربایجان شرقی  2=آذربایجان غربی  3=اردبیل  4=اصفهان  5=البرز
6=ایلام  7=بوشهر  8=تهران  9=چهارمحال  10=خراسان جنوبی
11=خراسان رضوی  12=خراسان شمالی  13=خوزستان  14=زنجان  15=سمنان
16=سیستان  17=فارس  18=قزوین  19=قم  20=کردستان
21=کرمان  22=کرمانشاه  23=کهگیلویه  24=گلستان  25=گیلان
26=لرستان  27=مازندران  28=مرکزی  29=هرمزگان  30=همدان  100=یزد

نگاشت شهر → استان: 101→1, 102→2, 103→3, 104→4, 105→5, 106→6, 107→7, 108→8, 109→9, 110→10, 111→11, 112→12, 113→13, 114→14, 115→15, 116→16, 117→17, 118→18, 119→19, 120→20, 121→21, 122→22, 123→23, 125→24, 126→25, 127→26, 128→27, 129→28, 130→29, 131→30, 132→100

تخصص‌ها (specialties.id) — دسته‌بندی برای توزیع واقعی

داخلی: 1,2,3,4,5,6,7,8,9,10,11,12
جراحی: 20,21,22,23,24,25,26,27,28,29,30
اطفال: 40,41,42,43,44,45
زنان: 60,61,62,63,64,65
روانپزشکی: 70,71,72,73,74
پوست: 80,81,82,83,84
چشم: 90,91,92,93,94,95,96,97,98
ENT: 100,101,102,103,104
ارتوپدی: 110,111,112,113,114,115,116
اورولوژی: 120,121,122,123,124
رادیولوژی: 130,131,132,133,134
انکولوژی: 150,151,152
طب فیزیکی: 170,171,172,173
دندانپزشکی: 180,181,182,183,184,185,186,187,188,189
اورژانس/عمومی: 190,200

خدمات پزشکی (doctor_services.id) — نمونه‌هایی برای هر تخصص

قلب: 101,102,103,104,105,110
گوارش: 201,202,203,210
ریه: 301,302,303,307
کلیه: 401,402,403,406
غدد: 501,502,503,505,506
روماتولوژی: 601,602,603,604
خون: 701,702,703,704
نورولوژی: 801,802,803,804,805
آلرژی: 901,902,903,905
عفونی: 1001,1002,1003
جراحی عمومی: 2101,2102,2103,2104,2105,2113
جراحی مغز: 2201,2202,2203,2207

بیمه‌ها (insurances.id)

1=تأمین اجتماعی  2=خدمات درمانی  3=نیروهای مسلح  4=کمیته امداد
5=بهزیستی  6=بیمه روستایی  7=ایران  8=آسیا  9=البرز
10=پارسیان  11=سامان  12=میهن  13=دانا  14=رازی  15=کوثر

ساختار weekly_schedules.setting (JSON)

آرایه ۷ عنصر (شنبه تا جمعه). هر عنصر:

{
  "sessions": [
    {
      "active": true,
      "location_id": <doctor_address.id>,
      "start_time": "09:00",
      "end_time": "13:00",
      "duration_per_patient": 20,
      "has_rest": true,
      "rest_interval": 60,
      "time_to_rest": 10,
      "patient_limit": null
    }
  ]
}

روزهای بدون کار: {"sessions": []}

وظایف

۱. ایجاد فایل seed_realistic_data.php

فایل را در ریشه پروژه (/var/www/html/seed_realistic_data.php) بساز. این فایل باید:

بخش A — پاک‌سازی (به ترتیب FK)

// حذف به ترتیب وابستگی FK
$conn->executeStatement('SET FOREIGN_KEY_CHECKS=0');
$conn->executeStatement('DELETE FROM weekly_schedules WHERE doctor_id IN (SELECT id FROM doctors)');
$conn->executeStatement('DELETE FROM doctor_addresses');
$conn->executeStatement('DELETE FROM doctor_specialties');
$conn->executeStatement('DELETE FROM doctor_expertise');
$conn->executeStatement('DELETE FROM doctor_insurances');
$conn->executeStatement('DELETE FROM doctor_cities');
$conn->executeStatement('DELETE FROM doctor_provinces');
$conn->executeStatement('DELETE FROM doctor_secretaries');
$conn->executeStatement('DELETE FROM clinic_doctors');
$conn->executeStatement('DELETE FROM clinic_specialties');
$conn->executeStatement('DELETE FROM clinic_services');
$conn->executeStatement('DELETE FROM clinic_insurances');
$conn->executeStatement('DELETE FROM patient_records');
$conn->executeStatement('DELETE FROM appointments');
$conn->executeStatement('DELETE FROM payments');
// حذف doctors, clinics, users (به جز ادمین‌ها)
$conn->executeStatement("DELETE d FROM doctors d");
$conn->executeStatement("DELETE c FROM clinics c");
$conn->executeStatement("DELETE u FROM users u WHERE JSON_CONTAINS(u.roles, '\"ROLE_DOCTOR\"') OR JSON_CONTAINS(u.roles, '\"ROLE_CLINIC\"') OR JSON_CONTAINS(u.roles, '\"ROLE_PATIENT\"') OR JSON_CONTAINS(u.roles, '\"ROLE_SECRETARY\"')");
$conn->executeStatement('SET FOREIGN_KEY_CHECKS=1');

بخش B — کلینیک نمونه کامل (تبریز)

یک کلینیک با همه فیلدها:

  • نام: کلینیک تخصصی امید تبریز
  • city_id=101, province_id=1
  • representation_id=101 (تبریز)
  • تمام specialties داخلی + قلب
  • بیمه‌های 1,2,3,7,8,9
  • خدمات 201,202,203,101,102,103

بخش C — دکتر نمونه کامل (تبریز)

دکتر کامل با:

  • تخصص قلب (id=3) + داخلی (id=2)
  • بیمه‌های 1,2,3,7
  • خدمات 101,102,103,104,110
  • آدرس مطب در تبریز + آدرس کلینیک امید
  • برنامه کاری: شنبه تا چهارشنبه ۹-۱۳ و ۱۴-۱۸، پنجشنبه ۹-۱۳، جمعه تعطیل
  • یک منشی
  • representation_id=101

بخش D — ۱۰۰ دکتر برای هر شهر (bulk generation)

برای شهرهای: [101,102,103,104,105,108,111,113,117,121,122,126,128,131,132] (۱۵ شهر مهم)

هر دکتر باید داشته باشد:

  • user با موبایل منحصربه‌فرد (فرمت: 09XXXXXXXXX — از ۰۹۱۰۰۱۰۰۰۰۰ به بالا)
  • نام واقعی فارسی (از لیست ۱۰۰ نام ایرانی)
  • پروفایل کامل: gender, degree, medical_system_code, info, rate
  • تخصص (توزیع واقعی بین تخصص‌ها)
  • ۲-۳ خدمات متناسب با تخصص
  • بیمه‌های 1,2 (پایه) + یک بیمه تکمیلی تصادفی
  • یک آدرس مطب در شهرش
  • برنامه کاری (۵ روز کاری)
  • representation_id برابر با id شهر

لیست نام‌های واقعی ایرانی (برای استفاده در generator):

$firstNames = ['علی', 'محمد', 'حسین', 'رضا', 'امیر', 'مهدی', 'سعید', 'احمد', 'حسن', 'جواد',
               'فاطمه', 'زهرا', 'مریم', 'سارا', 'نگین', 'الهه', 'نیلوفر', 'شیما', 'لیلا', 'نازنین',
               'کریم', 'ابراهیم', 'اکبر', 'ناصر', 'پیمان', 'بهروز', 'شاهین', 'کاوه', 'آرش', 'سهراب',
               'مینا', 'آزاده', 'ندا', 'رویا', 'پریسا', 'گلناز', 'سپیده', 'بهاره', 'شادی', 'فریده'];
$lastNames  = ['رضایی', 'محمدی', 'حسینی', 'علوی', 'موسوی', 'احمدی', 'کریمی', 'صادقی', 'جعفری',
               'مرادی', 'نجفی', 'تبریزی', 'اصفهانی', 'مشهدی', 'شیرازی', 'کرمانی', 'رشیدی', 'نظری',
               'ابراهیمی', 'قاسمی', 'یوسفی', 'منصوری', 'زارعی', 'ملکی', 'بهرامی', 'سلیمانی', 'نوری'];

توزیع واقعی تخصص‌ها در ۱۰۰ دکتر:

$specialtyGroups = [
    ['specs' => [200], 'services' => [], 'degree' => 'general', 'count' => 15],         // عمومی ۱۵
    ['specs' => [2,3], 'services' => [101,102,103,110], 'degree' => 'specialist', 'count' => 10],  // داخلی+قلب ۱۰
    ['specs' => [4], 'services' => [201,202,203,210], 'degree' => 'specialist', 'count' => 6],     // گوارش ۶
    ['specs' => [10], 'services' => [801,802,803,805], 'degree' => 'specialist', 'count' => 6],    // نورولوژی ۶
    ['specs' => [21], 'services' => [2101,2102,2103,2113], 'degree' => 'specialist', 'count' => 8],// جراحی ۸
    ['specs' => [61], 'services' => [], 'degree' => 'specialist', 'count' => 8],        // زنان ۸
    ['specs' => [41], 'services' => [], 'degree' => 'specialist', 'count' => 8],        // اطفال ۸
    ['specs' => [111], 'services' => [], 'degree' => 'specialist', 'count' => 7],       // ارتوپدی ۷
    ['specs' => [81,82], 'services' => [], 'degree' => 'specialist', 'count' => 6],     // پوست ۶
    ['specs' => [91], 'services' => [], 'degree' => 'specialist', 'count' => 6],        // چشم ۶
    ['specs' => [101], 'services' => [], 'degree' => 'specialist', 'count' => 5],       // ENT ۵
    ['specs' => [71], 'services' => [], 'degree' => 'specialist', 'count' => 5],        // روانپزشکی ۵
    ['specs' => [121], 'services' => [], 'degree' => 'specialist', 'count' => 4],       // اورولوژی ۴
    ['specs' => [181], 'services' => [], 'degree' => 'dentist', 'count' => 6],          // دندانپزشکی ۶
];
// جمع = 100

فرمت برنامه کاری (۷ روز شنبه تا جمعه):

function makeSchedule(int $addressId): string {
    $days = [];
    for ($i = 0; $i < 7; $i++) {
        if ($i === 6) { // جمعه تعطیل
            $days[] = ['sessions' => []];
        } elseif ($i === 5) { // پنجشنبه نیمه‌وقت
            $days[] = ['sessions' => [
                ['active' => true, 'location_id' => $addressId, 'start_time' => '09:00',
                 'end_time' => '13:00', 'duration_per_patient' => 20,
                 'has_rest' => false, 'rest_interval' => 60, 'time_to_rest' => 10, 'patient_limit' => null]
            ]];
        } else { // شنبه تا چهارشنبه
            $days[] = ['sessions' => [
                ['active' => true, 'location_id' => $addressId, 'start_time' => '09:00',
                 'end_time' => '13:00', 'duration_per_patient' => 20,
                 'has_rest' => true, 'rest_interval' => 60, 'time_to_rest' => 10, 'patient_limit' => null],
                ['active' => true, 'location_id' => $addressId, 'start_time' => '14:00',
                 'end_time' => '18:00', 'duration_per_patient' => 20,
                 'has_rest' => false, 'rest_interval' => 60, 'time_to_rest' => 10, 'patient_limit' => null],
            ]];
        }
    }
    return json_encode($days, JSON_UNESCAPED_UNICODE);
}

نکات مهم اجرا

  • نام فایل PHP: seed_realistic_data.php در ریشه پروژه
  • password_hash: از password_hash('Test@1234', PASSWORD_BCRYPT) برای همه کاربران
  • roles JSON: '["ROLE_USER","ROLE_DOCTOR"]' برای دکتر، '["ROLE_USER","ROLE_CLINIC"]' برای کلینیک
  • uuid: از Symfony\Component\Uid\Uuid::v4()->toRfc4122() یا bin2hex(random_bytes(8)) — باید unique باشد
  • موبایل منحصربه‌فرد: از counter شمارنده استفاده کن تا تکراری نشود
  • representation_id: برابر با city_id شهر مربوطه (چون cities.id = representations.id)
  • FK ها: weekly_schedule بعد از ایجاد doctor_address insert شود (نیاز به address.id دارد)
  • transaction: همه insert ها در یک transaction بزرگ بپیچ تا در صورت خطا rollback شود
  • echo پیشرفت: بعد از هر شهر تعداد دکتر ایجادشده را چاپ کن

دستور اجرا

ddev exec php seed_realistic_data.php

خروجی مورد انتظار

✅ پاک‌سازی کامل شد
✅ کلینیک امید تبریز ایجاد شد (id: X)
✅ دکتر نمونه تبریز ایجاد شد (id: Y)
🏙️ تبریز: 100 دکتر ایجاد شد
🏙️ تهران: 100 دکتر ایجاد شد
...
✅ پایان — مجموع X دکتر در Y شهر ایجاد شد