# مدل داده و پایگاه داده

پایگاه داده هدف **PostgreSQL 16** است. در محیط توسعه‌ی این مخزن، به دلیل نبود
Docker، همان اسکیما با **PGlite** (پیاده‌سازی PostgreSQL روی WASM) و **همان
مهاجرت‌های drizzle-kit** اجرا می‌شود. یعنی گویش SQL، نوع‌ها و محدودیت‌ها یکسان‌اند.

- تعریف اسکیما: `backend/src/database/schema/index.ts`
- مهاجرت تولیدشده: `backend/src/database/migrations/0000_superb_peter_quill.sql`
- داده نمونه: `backend/src/database/seed.ts`

## ۱. فهرست جدول‌ها (۴۴ جدول)

### هویت و مجوز
| جدول | توضیح |
|---|---|
| `users` | حساب کاربری؛ گذرواژه با **Argon2id** |
| `sessions` | نشست‌ها؛ توکن به‌صورت **هش SHA-256** ذخیره می‌شود، نه خام |
| `roles`, `permissions`, `role_permissions` | تعریف نقش و مجوز ریزدانه |
| `user_roles` | انتساب نقش با **دامنه** (`global` / `organization` / `business`) |

### جغرافیا و طبقه‌بندی
| جدول | توضیح |
|---|---|
| `regions` | درخت استان ← شهر ← منطقه (خودارجاع با `parent_id`) |
| `taxonomies` | دسته، موضوع، برچسب، دسته‌بندی گزارش — همه در یک جدول با فیلد `kind` |

### نهادها
| جدول | توضیح |
|---|---|
| `organizations` | سازمان‌ها؛ خودارجاع برای ساختار مادر/زیرمجموعه، دارای `sla_config` |
| `departments` | ادارات و واحدهای هر سازمان، با موقعیت جغرافیایی |
| `organization_services` | خدمات قابل ارائه و مهلت پاسخ هر خدمت |
| `organization_members` | عضویت کاربران در سازمان (پایه‌ی جداسازی چند-مستاجری) |
| `guilds` | اصناف؛ خودارجاع |
| `businesses`, `shops`, `business_offerings` | کسب‌وکار، شعب و کالا/خدمات |

### تحریریه
| جدول | توضیح |
|---|---|
| `articles` | خبر؛ شامل `status`, `editable_until`, `is_locked`, `current_revision` |
| `article_revisions` | **هر تغییر یک نسخه کامل**؛ هرگز حذف نمی‌شود |
| `article_corrections` | اصلاحیه‌های رسمی با دلیل و توضیح عمومی |
| `article_workflow_events` | تاریخچه‌ی گذارهای گردش کار |
| `comments` | دیدگاه‌ها با وضعیت `pending/approved/rejected` |

### گزارش مردمی
| جدول | توضیح |
|---|---|
| `reports` | گزارش خام شهروند + سطح حریم خصوصی |
| `report_evidence` | مدارک پیوست |
| `cases` | پرونده‌ی رسیدگی؛ `sla_due_at`, `sla_breached_at`, `escalation_level` |
| `case_events` | رویدادهای پرونده با `visibility` عمومی/داخلی |
| `official_responses` | پاسخ رسمی سازمان یا کسب‌وکار |
| `tasks` | وظایف داخلی سازمان که از پرونده مشتق می‌شوند |
| `routing_rules` | قواعد موتور مسیریابی |

### داده و آمار
| جدول | توضیح |
|---|---|
| `datasets` | مجموعه‌داده با `source_title`, `publisher`, `methodology`, `geographic_scope` |
| `dataset_points` | نقاط داده (`series_key`, `period_label`, `value`) |

### جست‌وجو
| جدول | توضیح |
|---|---|
| `search_documents` | نمایه‌ی یکپارچه‌ی همه موجودیت‌ها با `normalized_text` و facets |
| `search_synonyms` | مترادف‌های فارسی |
| `saved_searches` | جست‌وجوهای ذخیره‌شده + پرچم اعلان |
| `search_queries` | ثبت پرس‌وجوها برای کشف شکاف محتوایی (`result_count = 0`) |

### ارتباط، رسانه، پایش
| جدول | توضیح |
|---|---|
| `communication_channels` | کانال‌های تلگرام/ایتا/ایمیل هر سازمان |
| `outbound_messages` | صف خروجی با **وضعیت واقعی تحویل** (`queued/delivered/failed/unavailable`) |
| `organization_messages` | پیام رسمی بین سازمان‌ها با مهلت و درخواست اقدام |
| `media_assets` | فایل‌های بارگذاری‌شده + نوع تشخیص‌داده‌شده از Magic Number |
| `notifications`, `bookmarks`, `follows`, `reading_history` | تعامل کاربر |
| `analytics_events` | رویدادهای واقعی سامانه (مبنای همه آمارهای داخلی) |
| `audit_logs` | گزارش حسابرسی: کنش، بازیگر، قبل/بعد، IP |
| `settings` | تنظیمات زمان اجرا (مانند `editorial.edit_window_days`) |

## ۲. قواعد یکپارچگی مهم

- **`articles.editable_until`** هنگام نخستین انتشار محاسبه می‌شود:
  `published_at + editorial.edit_window_days`. تغییر بعدی این ستون توسط مسیرهای
  عادی ممکن نیست.
- **حذف نرم (`deleted_at`)** برای محتوای تحریریه؛ خبر منتشرشده اصلاً حذف نمی‌شود.
- **`cases.report_id`** یکتاست: هر گزارش حداکثر یک پرونده دارد؛ گزارش تکراری به
  پرونده‌ی موجود پیوند می‌خورد و پرونده‌ی جدید نمی‌سازد.
- **مختصات پرونده‌های `private_to_org`** در لایه‌ی سرویس حذف می‌شوند، پس اصلاً به
  پاسخ API راه پیدا نمی‌کنند (نه اینکه در فرانت پنهان شوند).

## ۳. نمایه‌گذاری (Index)

| نمایه | هدف |
|---|---|
| `articles(status, published_at DESC)` | فهرست اخبار و صفحه اصلی |
| `articles(slug)` یکتا | صفحه‌ی خبر |
| `cases(organization_id, status)` | فضای کاری سازمان |
| `cases(sla_due_at)` | پویش نقض مهلت |
| `search_documents(entity_type)` + GIN روی `normalized_text` | جست‌وجو |
| `audit_logs(entity_type, entity_id, created_at DESC)` | حسابرسی |

## ۴. اجرای محلی

```bash
# ساخت مهاجرت پس از تغییر اسکیما
npm run -w backend db:generate

# بازسازی کامل داده نمونه (توجه: داده فعلی پاک می‌شود)
rm -rf datacenter/database/pglite
npx tsx backend/src/database/seed.ts
```

> همه‌ی داده‌های نمونه با `data_source='demo'` علامت‌گذاری شده‌اند و در رابط کاربر با
> برچسب «داده نمونه» نمایش داده می‌شوند. گذرواژه‌ی همه حساب‌های نمونه:
> `Shahrnama@1404`.
