# DB Runbook (Arabic) - Paython

## 1) فهم سريع: Data vs Schema

- **Data** = السجلات داخل الجداول (rows).
- **Schema** = هيكل الجداول (columns/types/indexes/constraints).

> قاعدة ذهبية:
> - تعديل **Data** -> لا يحتاج `migration`.
> - تعديل **Schema** -> يحتاج `migration` (لو الموديل managed) أو SQL مباشر (لو unmanaged).

---

## 2) لو مسحت بيانات بالغلط

### الحالة A: عندك Backup
- اعمل restore من النسخة الاحتياطية (أفضل حل).

### الحالة B: بدون Backup
- أعد الاستيراد من ملف Excel/CSV/SQL.
- أو أدخل البيانات من الداشبورد يدويًا.

> حذف البيانات لا يُحل بـ `makemigrations`.

---

## 3) أوامر الميجريشن الصحيحة (للموديلات managed فقط)

من جذر المشروع:

```powershell
python manage.py makemigrations
python manage.py migrate
```

فحص حالة الميجريشن:

```powershell
python manage.py showmigrations
```

---

## 4) أهم نقطة في مشروعك: `legacydb` غالبًا `managed=False`

معظم جداول `legacydb/model_defs/...` معمولة:

- `managed = False`

هذا يعني:

- Django لا ينشئ/يعدل schema لهذه الجداول.
- `makemigrations` لن يديرها بالشكل الطبيعي.

### إذن لو عايز تغير schema في جداول legacy:

1. SQL مباشر على PostgreSQL (الموصى به هنا).
2. أو نقل الجدول إلى موديل managed جديد داخل app مناسبة.

---

## 5) سيناريوهات شائعة + الإجراء الصحيح

### سيناريو 1: عايز أمسح كل بيانات جدول
- SQL مباشر:
  - `DELETE FROM table_name;` (يحافظ على sequence غالبًا)
  - أو `TRUNCATE table_name RESTART IDENTITY CASCADE;` (أقوى وأسرع)

### سيناريو 2: عدلت حقل في `mainapp/models.py` (managed)
- نفذ:
  - `makemigrations`
  - `migrate`

### سيناريو 3: عدلت حقل في `legacydb/model_defs/...` (unmanaged)
- لا تعتمد على migration.
- نفذ SQL schema change يدويًا.

### سيناريو 4: خطأ type mismatch مثل `boolean = integer`
- تأكد نوع العمود الحقيقي في PostgreSQL.
- طابق نوع الحقل في موديل Django.
- استخدم bool في الفلاتر بدل 0/1 عند اللزوم.

---

## 6) قبل أي تعديل قاعدة بيانات (Checklist)

- [ ] أخذ Backup (إجباري في الإنتاج)
- [ ] تحديد: Data change أم Schema change؟
- [ ] التأكد هل الجدول managed أو unmanaged؟
- [ ] تجربة على بيئة local/staging أولًا
- [ ] توثيق التعديل (SQL أو migration file)

---

## 7) Backup/Restore سريع (PostgreSQL)

### Backup
```powershell
pg_dump -h 127.0.0.1 -U postgres -d paython_db -F c -f paython_db.backup
```

### Restore
```powershell
pg_restore -h 127.0.0.1 -U postgres -d paython_db --clean --if-exists paython_db.backup
```

---

## 8) أوامر مفيدة للتشخيص

```powershell
python manage.py check
python manage.py showmigrations
python manage.py dbshell
```

---

## 9) Recommendation لمشروع Paython

- القاعدة الافتراضية في `.env`: **MySQL** (`DB_ENGINE=django.db.backends.mysql`).
- PostgreSQL اختياري — غيّر `DB_*` في `.env` لو محتاجه.
- اعتبر `legacydb` جداول محتوى قديمة (Laravel) — Django يقرأها ولا ينشئها بـ `migrate` وحده.
- عند الاستقرار: راجع الجداول الحرجة هل تبقى `managed=False` أو تتحول managed تدريجيًا، وثبّت Backup دوري.

---

## 10) الميجريشن الكامل من صفر (محلي أو سيرفر جديد)

المشروع فيه **طبقتين** لقاعدة البيانات — لازم الاتنين:

| الطبقة | الأمر | بيعمل إيه |
|--------|--------|-----------|
| **Django** (`mainapp`, `auth`, …) | `migrate` | `auth_*`, `django_*`, `menus`, `mainapp_dashboardsectionperm` |
| **Legacy** (`legacydb`, محتوى الموقع) | `bootstrap_legacy` | `about`, `services`, `products`, … + استيراد البيانات |

> `migrate` **لوحده** يكفي لجداول Django فقط.  
> لو فتحت الموقع وطلع `Table 'python.about' doesn't exist` — نفّذ `bootstrap_legacy`.

### المتطلبات قبل البدء

1. نسخ `.env.example` → `.env` وضبط الاتصال:

```env
DB_ENGINE=django.db.backends.mysql
DB_NAME=python
DB_USER=root
DB_PASSWORD=
DB_HOST=127.0.0.1
DB_PORT=3306
```

2. إنشاء قاعدة البيانات في phpMyAdmin أو MySQL:

```sql
CREATE DATABASE python CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```

**قاعدة موجودة بـ `latin1` (كل الجداول):**

```powershell
python manage.py convert_db_utf8mb4
```

يحوّل الـ default للقاعدة + كل الجداول إلى `utf8mb4_unicode_ci`. للمعاينة فقط: `--dry-run`.

3. من جذر المشروع `c:\laragon\www\newpythoon` وتفعيل الـ venv إن وُجد.

---

### الخطوة 1 — ميجريشن Django (managed)

```powershell
cd c:\laragon\www\newpythoon
python manage.py check
python manage.py migrate
python manage.py showmigrations
```

المفروض كل الصفوف تبقى `[X]` لـ: `admin`, `auth`, `contenttypes`, `mainapp`, `sessions`.

**ملفات الميجريشن الحالية في `mainapp/migrations/`:**

| الملف | الجداول / التأثير |
|-------|-------------------|
| `0001_initial` | `menus` |
| `0002_dashboardsectionperm` | `mainapp_dashboardsectionperm` + صلاحيات الداشبورد |
| `0003_add_slider_dashboard_permission` | صلاحية Sliders |
| `0004_alter_dashboardsectionperm_options` | تحديث قائمة الصلاحيات |

لو عدّلت `mainapp/models.py`:

```powershell
python manage.py makemigrations mainapp
python manage.py migrate
```

---

### الخطوة 2 — جداول Legacy + البيانات

```powershell
python manage.py bootstrap_legacy
```

- **مرة واحدة** على قاعدة فاضية: ينشئ جداول `legacydb` الناقصة ويحمّل من  
  `backups/paython_dump_2026-05-08_20-06.json` (أو غيّر الملف بـ `--fixture-name`).

```powershell
# جداول فقط (بدون بيانات)
python manage.py bootstrap_legacy --schema-only

# بيانات فقط (الجداول لازم تكون موجودة)
python manage.py bootstrap_legacy --data-only

# ملف dump مختلف
python manage.py bootstrap_legacy --fixture-name=my_dump.json
```

**بديل (Laravel seed style):**

```powershell
python manage.py seed --class=DemoFixtureSeeder
```

> `seed` يستدعي `loaddata` على الملف الكامل — يفضّل `bootstrap_legacy` لأنه يتخطى تعارض `auth` و`django_*`.

**لا تشغّل:**

```powershell
python manage.py makemigrations legacydb   # ❌ غير مطلوب — الجداول unmanaged
```

---

### الخطوة 3 — مستخدم الداشبورد

```powershell
python manage.py createsuperuser
```

- تسجيل الدخول: `http://127.0.0.1:8000/accounts/login/`
- الداشبورد: `http://127.0.0.1:8000/en/admin/`
- Django Admin: `http://127.0.0.1:8000/django-admin/`

موظف بدون superuser (من shell):

```python
from django.contrib.auth.models import User
User.objects.create_user("editor", "e@example.com", "StrongPass123", is_staff=True)
```

---

### الخطوة 4 — Static (اختياري للسيرفر)

```powershell
python manage.py collectstatic --noinput
```

المصدر: `mainapp/static/` — المخرجات: مجلد `static/` في جذر المشروع.

---

### إعادة بناء قاعدة من الصفر (محلي — يحذف كل البيانات)

مثل Laravel ``migrate:fresh --seed``:

```powershell
python manage.py seed --fresh --force
```

- ``--fresh`` = ``flush`` + ``migrate`` + ``DatabaseSeeder``
- ``DatabaseSeeder`` ينشئ جداول legacy الناقصة + بيانات تجريبية (settings, sliders, services, menus, …) **بدون** ملف JSON
- اختياري في ``.env``: ``SEED_ADMIN_USERNAME``, ``SEED_ADMIN_PASSWORD``, ``SEED_ADMIN_EMAIL`` لإنشاء superuser تلقائياً
- تخصيص الاسم/الهاتف: ``SEED_SITE_NAME_EN``, ``SEED_SITE_NAME_AR``, ``SEED_SITE_EMAIL``, ``SEED_SITE_PHONE``

سيدر واحد فقط:

```powershell
python manage.py seed --class=ServicesSeeder
```

استيراد dump قديم (اختياري — ليس جزءاً من ``DatabaseSeeder``):

```powershell
python manage.py seed --class=DemoFixtureSeeder
```

يدوياً (بدون seed):

```powershell
python manage.py flush --no-input
python manage.py migrate
python manage.py bootstrap_legacy
python manage.py createsuperuser
```

---

### على السيرفر (cPanel / Passenger)

``passenger_wsgi.py`` **غير متتبّع في Git** (كل سيرفر مساره مختلف). أول نشر:

```bash
cp passenger_wsgi.py.example passenger_wsgi.py
# اختياري: export PASSENGER_PROJECT_HOME=/home/USER/public_html/domain
```

```bash
cd /home/USER/public_html/domain
source /home/USER/virtualenv/.../bin/activate
pip install -r requirements.txt

# .env على السيرفر (لا ترفعه من Git)
python manage.py migrate
python manage.py bootstrap_legacy
python manage.py collectstatic --noinput
python manage.py createsuperuser

touch tmp/restart.txt
```

إعدادات Apache/Passenger في `.htaccess` بجذر المشروع.

**إعادة توجيه بدون www → www (301):** مفعّل في `.htaccess` —  
`https://domain.com/...` → `https://www.domain.com/...`  
تأكد في `.env`: `SITE_URL=https://www.domain.com` (مع www).

---

### أخطاء شائعة

| الخطأ | السبب | الحل |
|-------|--------|------|
| `Table '…about' doesn't exist` | `migrate` فقط، بدون legacy | `python manage.py bootstrap_legacy` |
| `No such table: services` | نفس السبب | `bootstrap_legacy` |
| `migrate` لا يغيّر جدول legacy | `managed=False` | SQL يدوي أو `bootstrap_legacy --schema-only` |
| الداشبورد فاضي / 403 | لا يوجد user أو ليس `is_staff` | `createsuperuser` |
| تعارض عند `loaddata` | dump فيه `auth` + django | استخدم `bootstrap_legacy` بدل `loaddata` الكامل |

---

### Checklist سريع (نسخ ولصق)

```powershell
cd c:\laragon\www\newpythoon
python manage.py check
python manage.py migrate
python manage.py bootstrap_legacy
python manage.py createsuperuser
python manage.py runserver
```

---

## 11) Backup/Restore (MySQL — Laragon)

### Backup

```powershell
mysqldump -u root -p python > backups/python_%date:~-4,4%%date:~-10,2%%date:~-7,2%.sql
```

أو من phpMyAdmin: Export → قاعدة `python`.

### Restore

```powershell
mysql -u root -p python < backups\your_dump.sql
```

### Dump بصيغة Django (موجود في المشروع)

```powershell
python manage.py dumpdata --natural-foreign --natural-primary -o backups/paython_dump.json
```

---

## 12) أوامر تشخيص إضافية

```powershell
python manage.py check
python manage.py showmigrations
python manage.py dbshell
python manage.py shell -c "from django.contrib.auth.models import User; print(User.objects.count())"
python manage.py shell -c "from legacydb.model_defs.content.about import About; print(About.objects.count())"
```

---

## 13) جداول Laravel المتعارضة مع Django

### لا تحذفها أبدًا (Django شغال عليها)

| الجدول | الاستخدام |
|--------|-----------|
| `auth_user` | تسجيل دخول الداشبورد (`createsuperuser`) |
| `auth_group`, `auth_permission`, … | صلاحيات Django |
| `django_migrations` | سجل ميجريشن Django |
| `django_session` | جلسات الدخول |
| `django_content_type`, `django_admin_log` | نظام Django |

> موديلات `legacydb` اللي `db_table = 'auth_user'` إلخ **مرايا للقراءة فقط** — مش جدول تاني.

### آمن حذفها (Laravel قديم — Django مش محتاجها)

| النوع | الجداول |
|-------|---------|
| **مستخدمين Laravel** | `admins`, `users` |
| **Spatie / أدوار Laravel** | `permissions`, `roles`, `model_has_permissions`, `model_has_roles`, `role_has_permissions`, `password_reset_tokens` |
| **بنية Laravel** | `migrations`, `sessions`, `jobs`, `failed_jobs`, `job_batches`, `cache`, `cache_locks` |

**الداشبورد يستخدم:** `auth_user` فقط — **مش** `admins`.

### حذف تلقائي (بعد `migrate` + `createsuperuser`)

```powershell
# معاينة بدون حذف
python manage.py drop_laravel_shadow_tables --dry-run

# تنفيذ الحذف
python manage.py drop_laravel_shadow_tables
```

- يشيل FK من جداول مثل `finance_applications` → `admins` ثم يحذف الجداول.
- `bootstrap_legacy` لن يعيد إنشاء هذه الجداول في المستقبل.

### يدويًا (phpMyAdmin)

```sql
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS admins, users, permissions, roles;
DROP TABLE IF EXISTS model_has_permissions, model_has_roles, role_has_permissions;
DROP TABLE IF EXISTS password_reset_tokens, migrations, sessions;
DROP TABLE IF EXISTS jobs, failed_jobs, job_batches, cache, cache_locks;
SET FOREIGN_KEY_CHECKS = 1;
```

### ملاحظة: `menus`

جدول واحد `menus` — `mainapp.Menu` و`legacydb.Menus` يشيران لنفس الجدول. **لا تحذفه.** إدارة المنيو من الداشبورد أو Django.

### تنظيف الكود (تم)

حُذفت من `legacydb` الموديلات والـ Admin غير المستخدمة:

- `authn/*` — `Admins`, `Users`, `Roles`, `Permissions`, مرايا `auth_*`
- `django_core/*` — مرايا `django_*` + جداول Laravel (`jobs`, `cache`, `sessions`, …)

المستخدمون للداشبورد: **`django.contrib.auth`** (`createsuperuser` → `auth_user`).

### ترتيب مقترح على قاعدة فيها dump Laravel كامل

```powershell
python manage.py migrate
python manage.py bootstrap_legacy
python manage.py createsuperuser
python manage.py drop_laravel_shadow_tables
```

