{
  "title": "سرویس IAM",
  "slug": "team/backend/services/iam-service",
  "url": "/docs/team/backend/services/iam-service",
  "frontmatter": {
    "layout": "doc",
    "title": "IAM Service",
    "description": "سرویس مدیریت هویت و دسترسی‌ها — Authorization، نقش‌ها، مجوزها، خط‌مشی‌ها و حاکمیت کاربران در پلتفرم NONS",
    "version": "1.1.0",
    "status": "APPROVED",
    "author": "Backend Team",
    "owner": "Backend Team",
    "created_at": "2026-06-22",
    "updated_at": "2026-06-22",
    "tags": "",
    "reviewers": ""
  },
  "sections": [
    {
      "level": 1,
      "heading": "سرویس IAM",
      "content": "**IAM Service Blueprint**\n\n> **مستند رسمی معماری، مرزهای مسئولیت، مدل داده و تعاملات سرویس مدیریت هویت و دسترسی**\n\n---"
    },
    {
      "level": 2,
      "heading": "فهرست محتوا",
      "content": "1. [ماموریت و محدوده](#۱-ماموریت-و-محدوده)\n2. [جایگاه معماری](#۲-جایگاه-معماری)\n3. [اصول هسته](#۳-اصول-هسته)\n4. [دامنه‌های کسب‌وکاری](#۴-دامنه‌های-کسب‌وکاری)\n5. [Authorization Context](#۵-authorization-context)\n6. [Policy Engine](#۶-policy-engine)\n7. [ساختار دیتابیس](#۷-ساختار-دیتابیس)\n8. [APIهای REST](#۸-apihay-rest)\n9. [رویدادها](#۹-رویدادها)\n10. [حسابرسی (Audit)](#۱۰-حسابرسی)\n11. [استراتژی کش](#۱۱-استراتژی-کش)\n12. [Business Rule Ownership](#۱۲-business-rule-ownership)\n13. [معماری ران‌تایم](#۱۳-معماری-رانتایم)\n14. [تکنولوژی و استقرار](#۱۴-تکنولوژی-و-استقرار)\n15. [آینده توسعه](#۱۵-آینده-توسعه)\n\n---"
    },
    {
      "level": 2,
      "heading": "۱. ماموریت و محدوده",
      "content": "**Mission & Scope**\n\nIAM تنها لایه حاکمیتی (Governance Layer) پلتفرم NONS است. این سرویس تنها مرجع معتبر برای **تصمیم‌گیری‌های مجوزدهی (Authorization)**، **کنترل دسترسی (Access Control)**، **حاکمیت کاربران (User Governance)**، **خط‌مشی‌های پلتفرم** و **حقوق اشتراک (Entitlements)** می‌باشد."
    },
    {
      "level": 3,
      "heading": "مرزهای مسئولیت",
      "content": "| IAM مالک این موارد است | IAM مالک این موارد نیست |\n|------------------------|-------------------------|\n| نقش‌ها (Roles) | احراز هویت (Authentication) ← Auth Service / Kratos |\n| قابلیت‌ها (Capabilities) | رمز عبور، نشست (Session)، MFA ← Auth Service / Kratos |\n| مجوزها (Permissions) | توکن‌های دسترسی OAuth2 ← Token Service (Hydra) — صدور/ابطال توکن‌ها |\n| حقوق اشتراک (Entitlements) | قیمت‌گذاری و صورتحساب ← Billing Service |\n| محدودیت‌ها (Restrictions) | پروفایل کاربر ← User Service |\n| خط‌مشی‌ها (Policies) | محصولات، سفارشات، کیف پول ← سرویس‌های کسب‌وکاری |\n| وضعیت حساب (Status) | منطق کسب‌وکار سرویس‌ها ← هر سرویس |\n| لاگ‌های حسابرسی (Audit Logs) | مالکیت منابع (Resource Ownership) ← Relationship Service (آینده) |\n| Onboarding Flow (State Machine) | |\n| پالیسی تغییر Username/Avatar (rate-limit, cooldown, quota) | پروفایل کاربر ← User Service |\n\n> **تصمیم معماری (D6 / D8 / D9):** مسئولیت‌های زیر صراحتاً به IAM واگذار شده‌اند:\n> - **State Machine Onboarding:** چرخه وضعیت Onboarding در IAM/سرویس Onboarding است؛ User Service صرفاً Projection آن را نگهداری می‌کند.\n> - **پالیسی تغییر Username/Avatar:** محدودیت‌ها (تعداد مجاز در سال، Cooldown، حداقل عمر حساب، quota) توسط **IAM Policy Engine** تعریف و اعمال می‌شوند. User Service نتیجه بررسی پالیسی IAM را اجرا می‌کند و محدودیتی را هاردکد نمی‌کند."
    },
    {
      "level": 3,
      "heading": "قانون کلی معماری",
      "content": "```\nAuth Service  → «این شخص کیست؟» (هویت)\nUser Service  → «این شخص چگونه نمایش داده شود؟» (پروفایل)\nIAM Service   → «این شخص چه کاری اجازه دارد انجام دهد؟» (دسترسی)\nBilling       → «این شخص چه سطح خدماتی دارد؟» (اشتراک)\n```\n\n---"
    },
    {
      "level": 2,
      "heading": "۲. جایگاه معماری",
      "content": "**Architecture Position**\n\n```\nمرورگر / اپلیکیشن\n       │\n       ▼\n Auth Service / Kratos    ← احراز هویت (کیستی؟)\n       │\n       ▼\n┌──────────┐\n│   IAM    │    ← مجوزدهی (چه می‌تواند بکند؟)\n└────┬─────┘\n     │\n ┌───┼───┬───┬───┬───┬───┐\n ▼   ▼   ▼   ▼   ▼   ▼   ▼\nبازار سفارش کیف چت اختلاف نظارت ...\n```"
    },
    {
      "level": 3,
      "heading": "تفکیک لایه‌ها",
      "content": "| لایه | مسئولیت | سرویس |\n|------|---------|-------|\n| **احراز هویت** | کیستی؟ — ورود، ثبت‌نام، نشست، MFA | Auth Service / Ory Kratos |\n| **پروفایل** | چگونه نمایش داده شود؟ — Public ID, Username, Avatar, Preferences | User Service |\n| **مجوزدهی** | چه می‌تواند بکند؟ — نقش‌ها، مجوزها، خط‌مشی‌ها | IAM |\n| **مالکیت** (آینده) | چه کسی صاحب چیست؟ — روابط ریزدانه | Relationship Service |\n\n---"
    },
    {
      "level": 2,
      "heading": "۳. اصول هسته",
      "content": "**Core Principles**"
    },
    {
      "level": 3,
      "heading": "اصل ۱ — تفکیک دو منبع حقیقت: Proto برای تعریف، IAM برای runtime",
      "content": "> [!IMPORTANT]\n> ** Proto منبع حقیقت تعریف Keyهاست؛ IAM منبع حقیقت وضعیت runtime.**\n> - **Proto** (`contracts/permissions.proto`) منبع حقیقت برای **تعریف کلیدهای مجوز** است (نام‌ها، enum values)\n> - **IAM** منبع حقیقت برای **وضعیت runtime** است (کدام کاربر کدام مجوز را دارد، نقش‌ها، خط‌مشی‌ها)\n>\n> برای افزودن یک کلید مجوز جدید، اول باید در Proto تعریف شود، سپس در IAM ثبت گردد. IAM به‌تنهایی کلید جدید نمی‌سازد.\n\nهیچ سرویسی حق ایجاد، تغییر یا حذف مستقیم موارد زیر را ندارد:\n- نقش‌ها (Roles)\n- مجوزها (Permissions)\n- محدودیت‌ها (Restrictions)\n- خط‌مشی‌ها (Policies)\n- حقوق اشتراک (Entitlements)\n\nهمه تغییرات منحصراً از طریق IAM انجام می‌شود."
    },
    {
      "level": 3,
      "heading": "اصل ۲ — همه چیز داده است (Everything is Data)",
      "content": "موارد زیر هرگز نباید در کد به صورت سخت (Hardcoded) نوشته شوند:\n\n| مورد | نحوه ذخیره‌سازی |\n|------|-----------------|\n| نقش‌ها و قابلیت‌های مرتبط | دیتابیس |\n| تعاریف مجوزها و کلیدهای آن‌ها | دیتابیس |\n| حقوق اشتراک و مقادیر آن | دیتابیس |\n| انواع محدودیت‌ها | دیتابیس |\n| قوانین خط‌مشی | دیتابیس |\n\n**نتیجه:** تعریف یک نقش جدید یا اضافه کردن یک مجوز جدید بدون نیاز به استقرار (Deploy) کد جدید فقط با یک درخواست API امکان‌پذیر است."
    },
    {
      "level": 3,
      "heading": "اصل ۳ — بافت مجوزدهی محاسبه می‌شود، ذخیره نمی‌شود",
      "content": "Authorization Context هرگز به صورت دائمی ذخیره نمی‌شود. این شیء در لحظه از وضعیت کنونی تمام موجودیت‌های IAM محاسبه و در Redis با TTL کوتاه (۵ دقیقه) کش می‌شود."
    },
    {
      "level": 3,
      "heading": "اصل ۴ — منطق کسب‌وکار در سرویس‌های کسب‌وکاری می‌ماند",
      "content": "IAM داده‌ها و محدودیت‌ها را فراهم می‌کند. سرویس‌های کسب‌وکاری تصمیم نهایی را می‌گیرند.\n\n```\nIAM ارائه می‌دهد:   seller.product.limit = 100\nMarketplace:        current_products = 78\nتصمیم:              78 < 100 → مجاز است (Marketplace تصمیم می‌گیرد)\n```"
    },
    {
      "level": 3,
      "heading": "اصل ۵ — Business Rule هر سرویس در همان سرویس تعریف می‌شود",
      "content": "Policy و Business Rule توسط IAM ساخته نمی‌شوند. هر سرویس کسب‌وکاری مالک Business Rule خود است. سرویس در زمان تعریف شدن، قراردادهای دسترسی و Permission Contract مورد نیاز خود را ثبت می‌کند. IAM این قراردادها را دریافت، نگهداری و برای Authorization استفاده می‌کند.\n\n```\nMarketplace تعریف می‌کند:  product.create, product.publish\nIAM فقط مدیریت دسترسی به این قراردادها را انجام می‌دهد.\nIAM نباید بداند محصول چیست یا قانون فروش چیست.\n```\n\n---"
    },
    {
      "level": 2,
      "heading": "۴. دامنه‌های کسب‌وکاری",
      "content": "**Domain Model**"
    },
    {
      "level": 3,
      "heading": "۴.۱. کاربر (User)",
      "content": "یک ارجاع به هویت (Identity) در Auth Service. IAM هرگز رمز عبور، نشست یا داده‌های احراز هویت را ذخیره نمی‌کند. شناسه کاربر (userId) همان شناسه هویت در Auth Service است.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `identity_id` | UUID | شناسه کاربر در Auth Service (PK) |\n| `email` | VARCHAR | ایمیل (برای نمایش و جستجوی ادمین) |\n| `status` | ENUM | وضعیت حساب |\n\n> **نکته:** ایمیل در IAM صرفاً برای اهداف مدیریتی و لاگ‌ها ذخیره می‌شود. منبع حقیقت ایمیل Kratos است."
    },
    {
      "level": 3,
      "heading": "۴.۲. وضعیت حساب (Status)",
      "content": "| وضعیت | توضیح | اثر |\n|-------|-------|-----|\n| `ACTIVE` | حالت عادی | دسترسی کامل بر اساس نقش‌ها |\n| `PENDING_VERIFICATION` | منتظر تأیید | دسترسی محدود |\n| `LIMITED` | محدودیت جزئی | برخی عملیات مسدود |\n| `SUSPENDED` | تعلیق موقت | ورود مجاز، بیشتر عملیات مسدود |\n| `BANNED` | مسدودیت دائمی | ورود مسدود، هیچ دسترسی ندارد |\n| `ARCHIVED` | حذف نرم | بدون دسترسی، داده‌ها حفظ می‌شوند |\n\n**قوانین:**\n- فقط یک وضعیت فعال در هر لحظه\n- هر تغییر وضعیت در `status_history` ثبت می‌شود\n- تغییر وضعیت باعث بی‌اعتبارسازی فوری کش می‌شود\n- رویداد `nons.iam.user.status_changed` منتشر می‌گردد"
    },
    {
      "level": 3,
      "heading": "۴.۳. نقش (Role)",
      "content": "یک موقعیت کسب‌وکاری. کاربران می‌توانند همزمان چند نقش داشته باشند. نقش‌ها کاملاً پویا هستند و در دیتابیس تعریف می‌شوند.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `key` | VARCHAR | شناسه منحصربه‌فرد (مثلاً `SELLER`) |\n| `name` | VARCHAR | نام نمایشی |\n| `description` | TEXT | توضیحات (اختیاری) |\n\n**نقش‌های پیش‌فرض:**\n\n| نقش | توضیح |\n|-----|-------|\n| `BUYER` | خریدار |\n| `SELLER` | فروشنده |\n| `ADMIN` | مدیر |\n| `REVIEWER` | بازبین |\n| `SUPPORT_AGENT` | پشتیبانی |\n| `FINANCE_AGENT` | امور مالی |\n\n> **نکته:** پلن‌ها هرگز نباید به عنوان نقش نمایش داده شوند. یک فروشنده PREMIUM همچنان `role=SELLER` دارد با `plan=PREMIUM`."
    },
    {
      "level": 3,
      "heading": "۴.۴. قابلیت (Capability)",
      "content": "یک گروه‌بندی منطقی از مجوزهای مرتبط. قابلیت‌ها به نقش‌ها اختصاص می‌یابند. این لایه میانی امکان مدیریت دسته‌جمعی مجوزها را بدون اتصال مستقیم نقش‌ها به مجوزهای اتمی فراهم می‌کند.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `key` | VARCHAR | شناسه منحصربه‌فرد (مثلاً `SELLING`) |\n| `name` | VARCHAR | نام نمایشی |\n| `description` | TEXT | توضیحات (اختیاری) |\n\n**قابلیت‌های پیش‌فرض:**\n\n| قابلیت | مجوزهای نمونه |\n|--------|--------------|\n| `SELLING` | `product.create`, `product.edit`, `product.delete` |\n| `BUYING` | `order.create`, `order.cancel`, `review.create` |\n| `SUPPORT` | `ticket.view`, `ticket.resolve` |\n| `FINANCE` | `wallet.withdraw`, `wallet.view`, `report.finance` |\n\n**روابط:**\n```\nنقش (Role) ←→ قابلیت (Capability) ←→ مجوز (Permission)\n```"
    },
    {
      "level": 3,
      "heading": "۴.۵. مجوز (Permission)",
      "content": "یک کنش اتمی و نام‌گذاری شده. کلیدهای مجوز قراردادهای پایدار (Stable Contracts) بین IAM و سرویس‌های کسب‌وکاری هستند.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `key` | VARCHAR | شناسه منحصربه‌فرد (مثلاً `product.create`) |\n| `name` | VARCHAR | نام نمایشی |\n| `description` | TEXT | توضیحات (اختیاری) |\n\n**فرمت:** `resource.action` یا `resource.subresource.action`\n\n**نمونه‌ها:**\n- `product.create` — ایجاد محصول\n- `order.create` — ایجاد سفارش\n- `wallet.withdraw` — برداشت از کیف پول\n- `admin.access` — دسترسی به پنل مدیریت\n\n> **توجه:** کلیدهای مجوز قرارداد API بین IAM و سرویس‌های پایین‌دستی هستند. تغییر نام یک کلید، یک Breaking Change محسوب می‌شود."
    },
    {
      "level": 3,
      "heading": "۴.۶. حق اشتراک (Entitlement)",
      "content": "یک محدودیت یا feature flag که از نقش، پلن، خط‌مشی یا override کاربر می‌آید. IAM مالک **تعریف و مدیریت** Entitlement‌هاست، اما **قیمت‌گذاری و صورتحساب** در Billing Service انجام می‌شود.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `key` | VARCHAR | شناسه منحصربه‌فرد (مثلاً `seller.product.limit`) |\n| `name` | VARCHAR | نام نمایشی |\n| `value_type` | ENUM | `NUMBER` / `BOOLEAN` |\n| `default_value` | VARCHAR | مقدار پیش‌فرض |\n\n**نمونه‌ها:**\n- `seller.product.limit = 10` — محدودیت تعداد محصول\n- `daily.withdraw.limit = 5000` — محدودیت برداشت روزانه\n- `feature.analytics = true` — دسترسی به گزارش‌ها\n\n**اولویت تصمیم‌گیری (بالاترین اولویت برنده است):**\n\n1. **User Override** — همیشه بالاترین اولویت\n2. **Policy-generated** — تولیدشده توسط خط‌مشی\n3. **Role-based** — بر اساس نقش\n4. **Plan-based** — پایین‌ترین اولویت"
    },
    {
      "level": 3,
      "heading": "۴.۷. Override کاربر (User Override)",
      "content": "تغییرات مستقیم برای یک کاربر خاص که پیش‌فرض‌های نقش یا پلن را نادیده می‌گیرد.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `user_id` | UUID | کاربر هدف |\n| `entitlement_key` | VARCHAR | حق اشتراکی که override می‌شود |\n| `value` | VARCHAR | مقدار جدید |\n| `reason` | TEXT | دلیل (اختیاری) |\n| `created_at` | TIMESTAMPTZ | |\n| `expires_at` | TIMESTAMPTZ | انقضا (اختیاری) |"
    },
    {
      "level": 3,
      "heading": "۴.۸. محدودیت (Restriction)",
      "content": "محدودیت‌های اداری اعمال‌شده بر کاربر.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `key` | VARCHAR | شناسه منحصربه‌فرد (مثلاً `withdraw.blocked`) |\n| `name` | VARCHAR | نام نمایشی |\n| `description` | TEXT | توضیحات (اختیاری) |\n\n**انواع محدودیت (همگی پویا):**\n- `withdraw.blocked` — جلوگیری از برداشت\n- `selling.blocked` — جلوگیری از فروش\n- `chat.blocked` — جلوگیری از چت\n- `product.create.blocked` — جلوگیری از ایجاد محصول\n\n> محدودیت‌ها آخرین مرحله در محاسبه بافت هستند و همه چیز را override می‌کنند به جز `Status=BANNED`."
    },
    {
      "level": 3,
      "heading": "۴.۹. خط‌مشی (Policy)",
      "content": "قوانین حاکمیتی کسب‌وکاری که در IAM ذخیره و توسط Policy Engine اجرا می‌شوند.\n\n| بخش | توضیح |\n|-----|-------|\n| `condition` | شرط ارزیابی (metric, operator, value) |\n| `effect` | اثر در صورت برآورده شدن شرط |\n| `enabled` | فعال/غیرفعال |\n\n**DSL خط‌مشی:**\n\n```json\n{\n  \"name\": \"high-dispute-block-withdraw\",\n  \"enabled\": true,\n  \"condition\": {\n    \"metric\": \"seller.dispute_count\",\n    \"operator\": \">\",\n    \"value\": 3\n  },\n  \"effect\": {\n    \"type\": \"restriction.add\",\n    \"target\": \"withdraw.blocked\"\n  }\n}\n```\n\n**انواع اثر:**\n| نوع | توضیح |\n|-----|-------|\n| `restriction.add` | اضافه کردن محدودیت به کاربر |\n| `entitlement.set` | تنظیم مقدار حق اشتراک |"
    },
    {
      "level": 3,
      "heading": "۴.۱۰. Workspace",
      "content": "یک ناحیه قابل دسترسی در پلتفرم. Workspace در IAM فقط یک مفهوم **Authorization** است — IAM تصمیم می‌گیرد کاربر به کدام workspace دسترسی دارد، اما مسیردهی و UI خارج از IAM است.\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `key` | VARCHAR | شناسه (مثلاً `seller`) |\n| `name` | VARCHAR | نام نمایشی |\n| `required_permissions` | TEXT[] | مجوزهای مورد نیاز |\n\n**محیط‌های کاری پیش‌فرض:**\n\n| کلید | مجوز مورد نیاز |\n|------|---------------|\n| `seller` | `product.create` |\n| `admin` | `admin.access` |\n| `finance` | `wallet.view` |\n| `support` | `ticket.view` |\n\n---"
    },
    {
      "level": 2,
      "heading": "۵. Authorization Context",
      "content": "**Authorization Context**"
    },
    {
      "level": 3,
      "heading": "تعریف",
      "content": "Authorization Context خروجی محاسبه‌شده IAM است. این شیء که سرویس‌های پایین‌دستی برای تصمیمات مجوزدهی استفاده می‌کنند، هرگز به صورت دائمی ذخیره نمی‌شود و در لحظه محاسبه و در Redis کش می‌شود."
    },
    {
      "level": 3,
      "heading": "ساختار Context",
      "content": "```json\n{\n  \"schemaVersion\": 1,\n  \"userId\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"status\": \"ACTIVE\",\n  \"roles\": [\n    { \"key\": \"SELLER\", \"name\": \"Seller\" }\n  ],\n  \"permissions\": [\"product.create\", \"product.edit\"],\n  \"entitlements\": {\n    \"seller.product.limit\": \"100\",\n    \"feature.analytics\": \"true\",\n    \"daily.withdraw.limit\": \"50\"\n  },\n  \"restrictions\": [],\n  \"workspaces\": [\"seller\"],\n  \"plan\": { \"key\": \"PREMIUM\", \"name\": \"Premium\" },\n  \"generatedAt\": \"2026-06-22T10:00:00Z\",\n  \"expiresAt\": \"2026-06-22T10:05:00Z\"\n}\n```"
    },
    {
      "level": 3,
      "heading": "ترتیب محاسبه Context",
      "content": "| مرحله | منبع | خروجی |\n|-------|------|-------|\n| 1 | نقش‌های کاربر | مجموعه اولیه قابلیت‌ها و مجوزها |\n| 2 | قابلیت‌ها | لیست گسترش‌یافته مجوزها |\n| 3 | مجوزها | لیست نهایی مجوزهای اتمی |\n| 4 | پلن | مقادیر پایه حق اشتراک |\n| 5 | خط‌مشی‌ها | اعمال تغییرات ناشی از خط‌مشی |\n| 6 | Overrideهای کاربر | اعمال overrideها (بالاترین اولویت) |\n| 7 | محدودیت‌ها | مسدود یا محدود کردن کنش‌ها |\n| 8 | وضعیت | اعمال اثر سراسری وضعیت |"
    },
    {
      "level": 3,
      "heading": "منطق بررسی مجوز (Check Permission)",
      "content": "```\n1. اگر وضعیت BANNED باشد       → رد (reason: \"User is banned\")\n2. اگر وضعیت SUSPENDED باشد    → رد (reason: \"User is suspended\")\n3. اگر وضعیت ARCHIVED باشد     → رد (reason: \"Account is archived\")\n4. اگر مجوز در لیست نباشد      → رد (reason: \"Missing permission: {action}\")\n5. اگر محدودیت فعال باشد       → رد (reason: \"Blocked by restriction: {key}\")\n6. در غیر این صورت             → تأیید\n```\n\n---"
    },
    {
      "level": 2,
      "heading": "۶. Policy Engine",
      "content": "**Policy Engine**\n\nموتور Policy یک ماژول مجزاست که:\n1. خط‌مشی‌ها را از دیتابیس می‌خواند\n2. شرط (condition) را با متریک‌های ورودی ارزیابی می‌کند\n3. در صورت برآورده شدن شرط، اثر (effect) را اعمال می‌کند\n4. رویداد `nons.iam.policy.executed` را منتشر می‌کند\n5. نتیجه را در لاگ حسابرسی ثبت می‌کند"
    },
    {
      "level": 3,
      "heading": "محدودیت‌های نسخه اول (v1)",
      "content": "- شرایط فقط از مقایسه تک‌متریک پشتیبانی می‌کند (بدون AND/OR)\n- اجرای خط‌مشی از طریق API (اجرای مبتنی بر رویداد در برنامه آینده)\n- متریک‌ها در زمان ارزیابی ارائه می‌شوند (بدون جمع‌آوری داخلی متریک)\n\n---"
    },
    {
      "level": 2,
      "heading": "۷. ساختار دیتابیس",
      "content": "**Database Structure**"
    },
    {
      "level": 3,
      "heading": "دیاگرام روابط",
      "content": "```\nRole ─── RoleCapability ─── Capability ─── CapabilityPermission ─── Permission\n\nUser ─── UserRole ─── Role\nUser ─── UserRestriction ─── Restriction\nUser ─── UserOverride ─── Entitlement\nUser ─── StatusHistory\nUser ─── Plan ─── PlanEntitlement ─── Entitlement\n\nPolicy ─── { condition: JSON, effect: JSON }\n\nWorkspace ─── { required_permissions: TEXT[] }\n\nAuditLog (append-only)\n```"
    },
    {
      "level": 3,
      "heading": "جداول متعلق به IAM",
      "content": "| جدول | توضیح |\n|------|-------|\n| `users` | snapshot مدیریتی کاربران |\n| `roles` | تعاریف نقش‌ها |\n| `capabilities` | گروه‌بندی مجوزها |\n| `permissions` | مجوزهای اتمی |\n| `plans` | پلن‌های اشتراک (Entitlement definitions) |\n| `entitlements` | حقوق اشتراک |\n| `user_roles` | نگاشت کاربر-نقش |\n| `user_restrictions` | محدودیت‌های کاربر |\n| `user_overrides` | overrideهای کاربر |\n| `status_history` | تاریخچه وضعیت |\n| `plan_entitlements` | نگاشت پلن-حق اشتراک |\n| `role_capabilities` | نگاشت نقش-قابلیت |\n| `capability_permissions` | نگاشت قابلیت-مجوز |\n| `policies` | خط‌مشی‌ها |\n| `workspaces` | محیط‌های کاری |\n| `audit_logs` | لاگ حسابرسی append-only |\n\n---"
    },
    {
      "level": 2,
      "heading": "۸. APIهای REST",
      "content": "**REST APIs**\n\nتمامی مسیرها با پیشوند `/v1/iam` ارائه می‌شوند."
    },
    {
      "level": 3,
      "heading": "۸.۱. APIهای Context (مورد استفاده همه سرویس‌ها)",
      "content": "| Method | Path | توضیح |\n|--------|------|-------|\n| `GET` | `/v1/iam/me/context` | دریافت Authorization Context کاربر جاری |\n| `GET` | `/v1/iam/users/{id}/context` | دریافت Context کاربر مشخص (ادمین) |\n| `POST` | `/v1/iam/authorization/check` | بررسی مجوز خاص برای کاربر |\n\n**بررسی مجوز:**\n```http\nPOST /v1/iam/authorization/check\n{\n  \"userId\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"action\": \"product.create\"\n}\n```\n\n**پاسخ:**\n```json\n// 200 — مجاز\n{ \"data\": { \"allowed\": true } }\n\n// 200 — مسدود\n{ \"data\": { \"allowed\": false, \"reason\": \"restriction:selling.blocked\" } }\n```"
    },
    {
      "level": 3,
      "heading": "۸.۲. APIهای مدیریت کاربر",
      "content": "| Method | Path | توضیح |\n|--------|------|-------|\n| `GET` | `/v1/iam/users/{id}` | دریافت اطلاعات IAM کاربر |\n| `POST` | `/v1/iam/users/{id}/roles` | اختصاص نقش به کاربر |\n| `DELETE` | `/v1/iam/users/{id}/roles/{roleKey}` | حذف نقش از کاربر |\n| `PUT` | `/v1/iam/users/{id}/status` | تغییر وضعیت کاربر |\n| `GET` | `/v1/iam/users/{id}/status/history` | تاریخچه تغییر وضعیت |\n| `POST` | `/v1/iam/users/{id}/restrictions` | اضافه کردن محدودیت |\n| `DELETE` | `/v1/iam/users/{id}/restrictions/{key}` | حذف محدودیت |\n| `GET` | `/v1/iam/users/{id}/restrictions` | دریافت محدودیت‌ها |\n| `GET` | `/v1/iam/users/{id}/overrides` | دریافت overrideها |\n| `POST` | `/v1/iam/users/{id}/overrides` | اعمال override |\n| `DELETE` | `/v1/iam/users/{id}/overrides/{id}` | حذف override |\n| `PUT` | `/v1/iam/users/{id}/plan` | تغییر پلن کاربر |\n| `GET` | `/v1/iam/users/{id}/audit` | دریافت لاگ حسابرسی کاربر |"
    },
    {
      "level": 3,
      "heading": "۸.۳. APIهای پیکربندی",
      "content": "| Method | Path | توضیح |\n|--------|------|-------|\n| `POST` | `/v1/iam/roles` | ایجاد نقش |\n| `GET` | `/v1/iam/roles` | فهرست نقش‌ها |\n| `PATCH` | `/v1/iam/roles/{key}` | به‌روزرسانی نقش |\n| `DELETE` | `/v1/iam/roles/{key}` | حذف نقش |\n| `POST` | `/v1/iam/capabilities` | ایجاد قابلیت |\n| `GET` | `/v1/iam/capabilities` | فهرست قابلیت‌ها |\n| `PATCH` | `/v1/iam/capabilities/{key}` | به‌روزرسانی قابلیت |\n| `DELETE` | `/v1/iam/capabilities/{key}` | حذف قابلیت |\n| `POST` | `/v1/iam/permissions` | ایجاد مجوز |\n| `GET` | `/v1/iam/permissions` | فهرست مجوزها |\n| `PATCH` | `/v1/iam/permissions/{key}` | به‌روزرسانی مجوز |\n| `DELETE` | `/v1/iam/permissions/{key}` | حذف مجوز |\n| `POST` | `/v1/iam/plans` | ایجاد پلن |\n| `GET` | `/v1/iam/plans` | فهرست پلن‌ها |\n| `PATCH` | `/v1/iam/plans/{key}` | به‌روزرسانی پلن |\n| `DELETE` | `/v1/iam/plans/{key}` | حذف پلن |\n| `POST` | `/v1/iam/entitlements` | ایجاد حق اشتراک |\n| `GET` | `/v1/iam/entitlements` | فهرست حقوق اشتراک |\n| `PATCH` | `/v1/iam/entitlements/{key}` | به‌روزرسانی |\n| `DELETE` | `/v1/iam/entitlements/{key}` | حذف |\n| `POST` | `/v1/iam/policies` | ایجاد خط‌مشی |\n| `GET` | `/v1/iam/policies` | فهرست خط‌مشی‌ها |\n| `PATCH` | `/v1/iam/policies/{id}` | به‌روزرسانی |\n| `DELETE` | `/v1/iam/policies/{id}` | حذف |\n| `POST` | `/v1/iam/policies/{id}/execute` | اجرای دستی خط‌مشی |\n| `POST` | `/v1/iam/workspaces` | ایجاد workspace |\n| `GET` | `/v1/iam/workspaces` | فهرست workspaceها |\n| `PATCH` | `/v1/iam/workspaces/{key}` | به‌روزرسانی |\n| `DELETE` | `/v1/iam/workspaces/{key}` | حذف |\n| `GET` | `/v1/iam/audit` | فهرست لاگ حسابرسی |\n\n---"
    },
    {
      "level": 2,
      "heading": "۹. رویدادها",
      "content": "**Events**\n\nتمامی رویدادها مطابق استاندارد `ADR-EVENT-001` در دامنه `iam` تعریف می‌شوند."
    },
    {
      "level": 3,
      "heading": "رویدادهای منتشرشده (Outbound)",
      "content": "| رویداد | مصرف‌کنندگان | توضیح |\n|--------|-------------|-------|\n| `nons.iam.user.status_changed` | همه سرویس‌ها | تغییر وضعیت حساب (بحرانی) |\n| `nons.iam.user.role_assigned` | سرویس‌های مرتبط | نقش به کاربر اختصاص یافت |\n| `nons.iam.user.role_removed` | سرویس‌های مرتبط | نقش از کاربر گرفته شد |\n| `nons.iam.user.plan_changed` | billing-service, marketplace | پلن کاربر تغییر کرد |\n| `nons.iam.user.restriction_added` | wallet-service, marketplace | محدودیت اضافه شد |\n| `nons.iam.user.restriction_removed` | wallet-service, marketplace | محدودیت حذف شد |\n| `nons.iam.policy.executed` | notification-service, admin | خط‌مشی اجرا شد |\n| `nons.iam.user.onboarding_completed` | notification-service | Onboarding کاربر تکمیل شد |\n| `nons.iam.user.onboarding_state_changed` | user-service, notification-service | تغییر وضعیت State Machine Onboarding |"
    },
    {
      "level": 3,
      "heading": "رویدادهای مصرف‌شونده (Inbound)",
      "content": "| رویداد | Publisher | عکس‌العمل |\n|--------|-----------|-----------|\n| `nons.auth.user.registered` | auth-service | ایجاد کاربر در IAM |\n| `nons.user.profile.created` | user-service | همگام‌سازی اطلاعات پروفایل |"
    },
    {
      "level": 3,
      "heading": "ساختار رویداد (نمونه)",
      "content": "```json\n{\n  \"user_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"actor_id\": \"admin_xyz\",\n  \"old_status\": \"ACTIVE\",\n  \"new_status\": \"BANNED\",\n  \"reason\": \"نقض قوانین سرویس\"\n}\n```\n\n---"
    },
    {
      "level": 2,
      "heading": "۱۰. حسابرسی",
      "content": "**Audit**"
    },
    {
      "level": 3,
      "heading": "اصول",
      "content": "- هر کنش حاکمیتی باید در لاگ حسابرسی ثبت شود\n- لاگ‌ها append-only هستند (فقط create، هیچگاه update یا delete)\n- هر لاگ شامل snapshot قبل و بعد از تغییر است\n\n| Field | Type | توضیح |\n|-------|------|-------|\n| `id` | UUID PK | |\n| `actor_id` | UUID | انجام‌دهنده کنش |\n| `target_id` | UUID | هدف کنش |\n| `action` | VARCHAR | نوع کنش |\n| `entity` | VARCHAR | موجودیت |\n| `entity_id` | VARCHAR | شناسه موجودیت |\n| `before` | JSONB | snapshot قبل از تغییر |\n| `after` | JSONB | snapshot بعد از تغییر |\n| `detail` | TEXT | توضیحات |\n| `created_at` | TIMESTAMPTZ | |"
    },
    {
      "level": 3,
      "heading": "رویدادهای قابل حسابرسی",
      "content": "| رویداد | موارد ثبت‌شده |\n|--------|--------------|\n| `role.assigned` | actor, target_user, role |\n| `role.removed` | actor, target_user, role |\n| `plan.changed` | actor, target_user, old_plan, new_plan |\n| `restriction.added` | actor, target_user, restriction_key |\n| `restriction.removed` | actor, target_user, restriction_key |\n| `status.changed` | actor, target_user, old_status, new_status |\n| `policy.executed` | policy_id, target_user, condition_snapshot |\n| `override.applied` | actor, target_user, key, old_value, new_value |\n| `override.removed` | actor, target_user, key |\n\n---"
    },
    {
      "level": 2,
      "heading": "۱۱. استراتژی کش",
      "content": "**Cache Strategy**"
    },
    {
      "level": 3,
      "heading": "معماری",
      "content": "Authorization Context در Redis به ازای هر کاربر کش می‌شود. بی‌اعتبارسازی کش **همزمان و فوری** است — قبل از برگرداندن پاسخ API، کش پاک می‌شود."
    },
    {
      "level": 3,
      "heading": "کلید کش و TTL",
      "content": "```\nکلید: iam:context:{userId}\nTTL:  300 ثانیه (۵ دقیقه)\nFallback: اگر Redis در دسترس نباشد، Context مستقیماً از دیتابیس محاسبه می‌شود\n```"
    },
    {
      "level": 3,
      "heading": "رویدادهای بی‌اعتبارسازی",
      "content": "| تغییر | محدوده بی‌اعتبارسازی |\n|-------|---------------------|\n| نقش اختصاص/حذف شد | کش یک کاربر |\n| پلن تغییر کرد | کش یک کاربر |\n| محدودیت اضافه/حذف شد | کش یک کاربر |\n| وضعیت تغییر کرد | کش یک کاربر |\n| Override اعمال شد | کش یک کاربر |\n| خط‌مشی اجرا شد | کش یک کاربر |"
    },
    {
      "level": 3,
      "heading": "تضمین Ban/Suspend",
      "content": "```\n1. نوشتن وضعیت جدید در دیتابیس\n2. بی‌اعتبارسازی کش Redis برای آن کاربر\n3. انتشار رویداد nons.iam.user.status_changed\n4. برگرداندن 200 OK\n```\n\n> اگر بی‌اعتبارسازی کش شکست بخورد، نوشتن وضعیت برگردانده (Roll back) می‌شود. حالت جزئی برای عملیات Ban قابل قبول نیست.\n\n---"
    },
    {
      "level": 2,
      "heading": "۱۲. Business Rule Ownership",
      "content": "**Business Rule Ownership**"
    },
    {
      "level": 3,
      "heading": "اصل",
      "content": "Policy و Business Rule توسط IAM ساخته نمی‌شوند. هر سرویس کسب‌وکاری مالک Business Rule خود است و قراردادهای دسترسی خود را در IAM ثبت می‌کند."
    },
    {
      "level": 3,
      "heading": "مدل",
      "content": "| مرحله | توضیح |\n|-------|-------|\n| 1 | سرویس کسب‌وکاری Permissionهای مورد نیاز خود را تعریف و در IAM ثبت می‌کند |\n| 2 | IAM این Permissionها را نگهداری و برای Authorization استفاده می‌کند |\n| 3 | سرویس کسب‌وکاری در زمان اجرا با IAM بررسی مجوز می‌کند |"
    },
    {
      "level": 3,
      "heading": "مثال",
      "content": "```\nMarketplace:\n  - تعریف: product.create, product.publish\n  - بررسی: POST /v1/iam/authorization/check { userId, action: \"product.create\" }\n  - IAM پاسخ می‌دهد: allowed / denied\n\nBilling:\n  - تعریف: seller.product.limit\n  - IAM ذخیره می‌کند: premium.seller.product.limit = 500\n  - Marketplace می‌پرسد: \"کاربر چند محصول می‌تواند داشته باشد؟\"\n```\n\n---"
    },
    {
      "level": 2,
      "heading": "۱۳. معماری ران‌تایم",
      "content": "**Runtime Architecture**\n\n```mermaid\ngraph TD\n    Client[كلاينت] -->|GET /v1/iam/**| GW[Traefik Gateway]\n    GW -->|ForwardAuth| Auth[Auth Service]\n    Auth -->|X-User-Id| GW\n    GW -->|Route| IAM[IAM Service]\n    IAM -->|Read / Write| DB[(PostgreSQL)]\n    IAM -->|Cache| Redis[(Redis)]\n    \n    Auth -->|nons.auth.user.registered| NATS[NATS JetStream]\n    User[User Service] -->|nons.user.profile.created| NATS\n    NATS -->|consume| IAM\n    \n    IAM -->|nons.iam.user.status_changed| NATS\n    IAM -->|nons.iam.policy.executed| NATS\n    \n    NATS -->|consume| BusSvc[Business Services]\n    BusSvc -->|POST /v1/iam/authorization/check| IAM\n```"
    },
    {
      "level": 3,
      "heading": "ماتریس وابستگی",
      "content": "| سرویس | نوع ارتباط | جهت |\n|-------|-----------|------|\n| **Auth Service** | رویداد `nons.auth.user.registered` | ورودی |\n| **User Service** | رویداد `nons.user.profile.created` | ورودی |\n| **Business Services** | REST: `POST /authorization/check` | ورودی/خروجی |\n| **Traefik Gateway** | Forward به `/v1/iam/...` | ورودی |\n| **Redis** | کش Authorization Context | داخلی |\n| **PostgreSQL** | دیتابیس دائمی | داخلی |\n\n---"
    },
    {
      "level": 2,
      "heading": "۱۴. تکنولوژی و استقرار",
      "content": "**Technology & Deployment**\n\n| مؤلفه | فناوری |\n|-------|--------|\n| **زبان** | Go |\n| **دیتابیس** | PostgreSQL (مستقل) |\n| **کش** | Redis |\n| **صف پیام** | NATS JetStream |"
    },
    {
      "level": 3,
      "heading": "متغیرهای محیطی",
      "content": "| متغیر | پیش‌فرض | توضیح |\n|-------|---------|-------|\n| `PORT` | `3004` | پورت HTTP |\n| `DATABASE_URL` | `postgresql://iam:secret@localhost:5432/iam_db` | کانکشن دیتابیس |\n| `REDIS_URL` | `redis://localhost:6379` | آدرس Redis |\n| `NATS_URL` | `nats://localhost:4222` | آدرس NATS |"
    },
    {
      "level": 3,
      "heading": "دیتابیس",
      "content": "- موتور: PostgreSQL\n- دیتابیس مستقل: `iam_db`\n- مهاجرت: پوشه `migrations/`\n\n---"
    },
    {
      "level": 2,
      "heading": "۱۵. آینده توسعه",
      "content": "**Future Extensions**\n\n| قابلیت | توضیح |\n|--------|-------|\n| **Relationship Service** | سرویس مجزا برای مالکیت منابع (Resource Ownership) با معماری ReBAC |\n| **Policy Event Triggers** | اجرای خودکار خط‌مشی در پاسخ به رویدادهای سرویس‌ها |\n| **Advanced Policy Conditions** | پشتیبانی از AND/OR/NOT در شرایط خط‌مشی |\n| **Bulk Operations** | APIهای گروهی برای تغییر وضعیت، نقش و محدودیت |\n| **Webhook Notifications** | ارسال رویدادهای حاکمیتی به سیستم‌های خارجی |\n\n---"
    },
    {
      "level": 2,
      "heading": "مستندات مرتبط",
      "content": "- [معماری پلتفرم](../../platform/Architecture.md)\n- [استاندارد نام‌گذاری رویدادها (ADR-EVENT-001)](../../platform/ADR/ADR-EVENT-001.md)\n- [User Service Blueprint](./user-service.md)\n- [استاندارد پاسخ API](../standard/api-response-format.md)\n- <a href=\"../../../../../nons-api/catalog/events/iam/\">ایونت کاتالوگ IAM</a>"
    }
  ]
}