# نموذج قاعدة البيانات — Database Schema (ERD)

## الجداول الأساسية

### users (جميع المستخدمين)

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| name | string | الاسم الكامل |
| email | string unique | |
| password | string | مشفر bcrypt |
| phone | string nullable | |
| profile_photo_id | bigint FK → media.id | صورة الملف الشخصي (Spatie) |
| lang | enum('en','tr') default 'en' | لغة الواجهة |
| fcm_token | string nullable | Token إشعارات الجهاز |
| is_active | boolean default true | تعطيل/تفعيل الحساب |
| created_at / updated_at | timestamps | |
| deleted_at | softDeletes | |

### roles & permissions (Spatie)

جداول Spatie القياسية:
- `roles` — الأدوار (Parent, Teacher, Admin, + أدوار مخصصة)
- `permissions` — الصلاحيات الفردية
- `role_has_permissions` — علاقة الدور بالصلاحية
- `model_has_roles` — علاقة المستخدم بالدور
- `model_has_permissions` — صلاحيات مباشرة لمستخدم

### students

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| first_name | string | اسم الطالب |
| last_name | string | الكنية |
| birth_date | date | تاريخ الميلاد |
| gender | enum('male','female') | |
| class_id | bigint FK → classes.id | الصف الحالي |
| enrollment_date | date | تاريخ التسجيل |
| status | enum('active','inactive','graduated') | حالة الطالب |
| allergies | text nullable | الحساسيات (نص بسيط، مثال: "peanuts, lactose") |
| notes | text nullable | ملاحظات عامة |
| created_at / updated_at | timestamps | |
| deleted_at | softDeletes | |

### parent_student (Pivot)

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| parent_id | bigint FK → users.id | ولي الأمر |
| student_id | bigint FK → students.id | الطالب |
| relationship | enum('father','mother','guardian','other') | صلة القرابة |
| is_primary | boolean default false | ولي الأمر الأساسي |
| receives_notifications | boolean default true | استلام الإشعارات |

### teacher_class (Pivot)

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| teacher_id | bigint FK → users.id | المعلم |
| class_id | bigint FK → classes.id | الصف |
| is_primary | boolean default false | المعلم الأساسي للصف |
| academic_year | string | السنة الدراسية |

### classes

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| name | string | اسم الصف (مثلاً: "صف الفراشات") |
| grade | string | المستوى العمري |
| age_min | int nullable | الحد الأدنى للعمر (بالشهور) |
| age_max | int nullable | الحد الأعلى للعمر |
| has_nap_time | boolean default true | هل لديه وقت قيلولة |
| nap_start_time | time nullable | بداية القيلولة |
| nap_end_time | time nullable | نهاية القيلولة |
| academic_year | string | السنة الدراسية |
| is_active | boolean default true | |
| created_at / updated_at | timestamps | |

---

## جداول العمليات اليومية

### attendances

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| student_id | bigint FK → students.id | |
| class_id | bigint FK → classes.id | |
| date | date | تاريخ الحضور |
| status | enum('present','absent','late','left_early') | حالة الحضور |
| arrival_time | time nullable | وقت الوصول |
| departure_time | time nullable | وقت المغادرة |
| recorded_by | bigint FK → users.id | من سجل الحضور (معلم) |

### meals

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| name | string | اسم الوجبة (فطور، غداء، عصر) |
| type | enum('breakfast','lunch','snack') | نوع الوجبة |

### meal_records

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| student_id | bigint FK → students.id | |
| meal_id | bigint FK → meals.id | الوجبة |
| date | date | التاريخ |
| status | enum('all','little','none','good_appetite','with_help') | حالة التناول |
| notes | text nullable | ملاحظات |

> **تنبيه:** عند توزيع الوجبات، تُعرض الحساسيات (من حقل `students.allergies`) بجانب اسم الطالب ليتمكن المعلم من الانتباه.

| recorded_by | bigint FK → users.id | المعلم المسجل |

### meal_plans (جدولة الوجبات)

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| meal_id | bigint FK → meals.id | الوجبة |
| date | date | التاريخ |
| description | string | وصف الوجبة المجدولة |

### sleep_records

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| student_id | bigint FK → students.id | |
| date | date | |
| status | enum('slept','not_slept','rested_only') | حالة النوم |
| duration | int nullable | مدة النوم بالدقائق (اختياري) |
| notes | text nullable | ملاحظات |
| recorded_by | bigint FK → users.id | |

---

## جداول الأنشطة والصور

### activities

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| title | string | اسم النشاط |
| description | text | وصف النشاط |
| objective | string | الهدف/المهارة المكتسبة |
| class_id | bigint FK → classes.id | الصف المستهدف |
| date | date | تاريخ النشاط |
| type | enum('scheduled','ad_hoc') | مجدول أم مباشر |
| published | boolean default false | منشور للأهالي |
| created_by | bigint FK → users.id | المعلم الناشر |

### activity_schedules (جدولة الأنشطة)

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| class_id | bigint FK → classes.id | |
| title | string | اسم النشاط المجدول |
| description | text | |
| objective | string | |
| day_of_week | smallint | يوم الأسبوع (0=أحد ... 6=سبت) |
| start_time | time | |
| end_time | time | |
| is_recurring | boolean | متكرر أسبوعياً |

### media_permissions (صلاحيات الصور)

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| media_id | bigint FK → media.id | الملف |
| student_id | bigint FK → students.id nullable | إذا خاص بطالب معين |
| class_id | bigint FK → classes.id nullable | إذا لصف كامل |
| visibility | enum('admin_only','teachers','parents_all','parents_tagged') | مدى الرؤية |
| requires_approval | boolean | هل يحتاج موافقة إدارة |
| approved | boolean | تمت الموافقة |
| approved_by | bigint FK → users.id nullable | من وافق |
| uploaded_by | bigint FK → users.id | من رفع |

---

## جداول الإعلانات والإشعارات

### announcements

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| title | string | عنوان الإعلان |
| body | text | المحتوى |
| scope | enum('all','class','individual') | نطاق الإعلان |
| target_class_id | bigint FK → classes.id nullable | إذا scope = class |
| target_user_id | bigint FK → users.id nullable | إذا scope = individual |
| created_by | bigint FK → users.id | الناشر |
| published_at | timestamp | وقت النشر |
| expires_at | timestamp nullable | تاريخ انتهاء الإعلان |

### announcement_reads

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| announcement_id | bigint FK → announcements.id | |
| user_id | bigint FK → users.id | |
| read_at | timestamp | |

### notifications

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | — (UUID string) |
| type | string | نوع الإشعار (class name) |
| notifiable_type | string | polymorphic |
| notifiable_id | bigint | polymorphic |
| data | jsonb | محتوى الإشعار |
| read_at | timestamp nullable | |
| created_at | timestamp | |

---

## جداول "أنا قادم"

### pickup_alerts

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| parent_id | bigint FK → users.id | ولي الأمر |
| student_id | bigint FK → students.id | الطالب |
| class_id | bigint FK → classes.id | الصف |
| estimated_minutes | enum('5','10','15','at_gate') | الوقت المتوقع |
| status | enum('pending','notified','completed','cancelled') | حالة التنبيه |
| notified_at | timestamp nullable | وقت إرسال الإشعار |

---

## جدول الإعدادات (Settings)

### settings

| العمود | النوع | وصف |
|--------|-------|------|
| id | bigint PK | |
| key | string unique | مفتاح الإعداد |
| value | jsonb | القيمة |
| group | string | مجموعة الإعداد |

**أمثلة للإعدادات:**
- `photos.require_approval` = true/false
- `school.name` = "Bilgi Ağacı Anaokulu"
- `school.working_hours.start` = "08:00"
- `school.working_hours.end` = "17:00"
- `academic.current_year` = "2025-2026"

---

## Spatie Media Library (جدول وسائط)

الجدول الأساسي الذي تنشئه Spatie:
- `media` — يحتوي file_name, mime_type, disk, collection_name, model (polymorphic) وغيرها.
- الـ `disk` سيكون `r2`.

---

## العلاقات الرئيسية (مخطط التدفق)

```
users (polymorphic roles via Spatie)
  │
  ├──[parent_student]── students ──[attendance, meal_records, sleep_records]
  │                          │
  ├──[teacher_class]─── classes ──[activities, activity_schedules, meal_plans]
  │
  └── announcements, pickup_alerts

students ── media (via Spatie polymorphic)
activities ── media (via Spatie polymorphic)
announcements ── announcement_reads (1:M)
media ── media_permissions (1:1)
```

---

## الفهارس المطلوبة (Indexes)

| الجدول | العمود | السبب |
|--------|--------|-------|
| attendances | (student_id, date) | استعلامات الحضور اليومية |
| attendances | (class_id, date) | عرض حضور الصف بالكامل |
| meal_records | (student_id, date) | متابعة وجبات طالب |
| sleep_records | (student_id, date) | متابعة نوم طالب |
| activities | (class_id, date) | عرض نشاطات الصف |
| media | (model_type, model_id) | Spatie polymorphic |
| pickup_alerts | (class_id, status) | تنبيهات قيد الانتظار للصف |
| announcements | (scope, published_at) | جلب الإعلانات النشطة |

---

## ملاحظات التصميم

1. **المستخدمون موحدون في جدول users واحد** مع Spatie Permissions لتعدد الأدوار. هذا يسمح لمعلم أن يكون ولي أمر في نفس الوقت بصلاحيات مختلفة.
2. **media_permissions** هي الجسر بين Spatie Media ومصفوفة الصلاحيات — تتحكم بمن يرى الصورة.
3. **إعدادات dynamic** عبر جدول settings تسمح للإدارة بتفعيل/تعطيل مميزات دون تعديل الكود.
4. **اللغة** الإنجليزية هي الأساس (en)، مع localization للتركية (tr) — يتم التخزين بـ en والترجمة تتم في الـ frontend.
5. **تم إلغاء نظام المراسلة** — المحادثات مستبدلة بالإعلانات والإشعارات فقط.
6. **الحساسيات تُخزن كحقل نصي بسيط في جدول students وليس كجدول منفصل** (مثال: "peanuts, lactose"). تُعرض بجانب اسم الطالب أثناء توزيع الوجبات.
7. **الوجبات موحدة لكل الروضة وليست لكل صف** — جدول meal_plans لا يحتوي على class_id، والوجبات تُطبق على مستوى الروضة بالكامل.
