{
  "title": "تصمیم معماری: معماری Pool Service و مرزهای مسئولیت Username/Avatar/Onboarding",
  "slug": "team/platform/ADR/ADR-Backend-007",
  "url": "/docs/team/platform/ADR/ADR-Backend-007",
  "frontmatter": {
    "layout": "doc",
    "title": "'ADR-Backend-007: معماری Pool Service و تثبیت مرزهای مسئولیت Username/Avatar/Onboarding'",
    "description": "Architectural Decision Record documenting the introduction of Pool Service as a centralized Reference Data and material generation source, and clarifying ownership boundaries for username generation, avatar pool, reserved usernames, onboarding state, user status, and change policies.",
    "version": "1.0.0",
    "status": "PROPOSED",
    "author": "Backend Team",
    "owner": "Backend Team",
    "created_at": "2026-07-15",
    "updated_at": "2026-07-15",
    "tags": "",
    "reviewers": ""
  },
  "sections": [
    {
      "level": 1,
      "heading": "تصمیم معماری: معماری Pool Service و مرزهای مسئولیت Username/Avatar/Onboarding",
      "content": "**Architectural Decision Record — Pool Service & Ownership Boundaries**\n\n> **ADR-Backend-007 — Proposed (Rev. 1.0)**\n\n---"
    },
    {
      "level": 2,
      "heading": "وضعیت (Status)",
      "content": "PROPOSED (پیشنهاد شده — در انتظار تایید تیم)\n\n---"
    },
    {
      "level": 2,
      "heading": "تاریخ (Date)",
      "content": "2026-07-15\n\n---"
    },
    {
      "level": 2,
      "heading": "زمینه (Context)",
      "content": "پس از بررسی پیاده‌سازی فعلی `user-service` (که تولید تصادفی Username و ویرایش آن را پیاده کرده بود) در مقابل [blueprint.md](../../backend/services/user-service/blueprint.md) و [user-service.md](../../backend/services/user-service.md)، تضادهای زیر شناسایی شد:\n\n۱. **منبع تولید Username مشخص نبود:** کد فعلی کلمات (adjective/noun) را در خود هاردکد کرده بود و Registry صرفاً برای یکتایی استفاده می‌شد — هیچ منبع متمرکزی برای مواد اولیه تولید وجود نداشت.\n\n۲. **انتشار دوگانه رویداد:** تغییر Username هم در `nons.user.profile.changed` و هم به صورت بالقوه در جای دیگر منتشر می‌شد (نقض قانون ۵).\n\n۳. **تضاد Onboarding:** blueprint ادعا می‌کرد User Service مالک Onboarding است، در حالی که State Machine Onboarding در IAM تعریف شده است.\n\n۴. **وضعیت حساب (Status):** blueprint مقدار اولیه را `PENDING` و تغییر آن را توسط User Service می‌دانست، در حالی که وضعیت باید از IAM بازتاب شود و مقدار اولیه در عمل `ACTIVE` است.\n\n۵. **پالیسی تغییر Username/Avatar:** هیچ مرجع واحدی برای محدودیت‌های تغییر (cooldown، quota، rate-limit) تعریف نشده بود.\n\n۶. **همپوشتی احتمالی با Currency Service:** داده‌های مرجع ارز (ISO codes و غیره) نیازمند منبع واحد بودند.\n\nاین ADR تصمیمات D1–D11 را برای رفع این تضادها و ایجاد سرویس Pool تثبیت می‌کند.\n\n---"
    },
    {
      "level": 2,
      "heading": "تصمیمات مصوب (Decisions)",
      "content": ""
    },
    {
      "level": 3,
      "heading": "D1. سرویس جدید: Pool Service",
      "content": "یک سرویس دامنه جدید با نام **Pool Service** معرفی می‌شود که مالک **Reference Data** و **مواد اولیه تولید** (curated pools) است. Pool Service یک سرویس مستقل با دیتابیس PostgreSQL خود و Read API (REST) است و توسط سایر سرویس‌ها مصرف می‌شود. جزئیات در [blueprint.md](../../backend/services/pool-service/blueprint.md) و [README.md](../../backend/services/pool-service/README.md)."
    },
    {
      "level": 3,
      "heading": "D2. Registry فقط مالک Username است؛ Generator از Pool مواد می‌گیرد",
      "content": "- `username_registry` **فقط و فقط** یکتایی و تخصیص Username را مدیریت می‌کند — منبع تولید نیست.\n- منطق Generator (الگوی `adjective_noun_NNN`) در **Consumer** (user-service) باقی می‌ماند اما مواد اولیه (لیست adjectives/nouns، طول/ساختار) را از **Pool Service** می‌گیرد.\n- این تفکیک در §۶ و §۷ [user-service.md](../../backend/services/user-service.md) تثبیت شد."
    },
    {
      "level": 3,
      "heading": "D3. ساختار مواد Username و API رزرو",
      "content": "- Pool Service لیست‌های adjectives و nouns را نگهداری می‌کند (قابل مدیریت توسط ادمین).\n- هر ماده دارای `id`, `value`, `category`, `status` (active/inactive) است.\n- Pool Service یک **Reserve API** ارائه می‌دهد تا Consumer پس از تولید یک نامتشابه، آن را reserve کند (قفل اتمیک برای جلوگیری از race)."
    },
    {
      "level": 3,
      "heading": "D4. Avatar Pool",
      "content": "- آواتارها منابع **curated** هستند که منبع آن‌ها Pool Service است (شامل متادیتا: skin tone, style, category, tags).\n- user-service متادیتای آواتار را از Pool می‌گیرد؛ فایل‌های فیزیکی در MVP موقتاً در Pool Service ذخیره می‌شوند (ر.ک. C8 / §۱۳ blueprint) و در آینده به Storage Service مهاجرت می‌کنند."
    },
    {
      "level": 3,
      "heading": "D5. لیست RESERVED و بررسی الگو",
      "content": "- لیست Usernameهای **RESERVED** (ادمین، برند، کلمات ممنوعه) توسط ادمین از طریق Pool API مدیریت می‌شود.\n- بررسی الگو (regex) برای جلوگیری از نام‌های توهین‌آمیز یا نقض‌کننده کماکان در user-service اعمال می‌شود (منطق محلی)."
    },
    {
      "level": 3,
      "heading": "D6. مالکیت Onboarding → IAM",
      "content": "- **State Machine Onboarding** در IAM (یا سرویس Onboarding تخصصی) است.\n- user-service صرفاً یک **Projection** از وضعیت Onboarding نگهداری می‌کند و چرخه وضعیت را هدایت نمی‌کند.\n- این تضاد در §۱۳ [user-service.md](../../backend/services/user-service.md) اصلاح شد."
    },
    {
      "level": 3,
      "heading": "D7. وضعیت حساب (Status) بازتاب‌دهنده IAM است",
      "content": "- user-service مالک وضعیت نیست؛ وضعیت را از IAM بازتاب می‌دهد.\n- مقدار اولیه کاربر جدید **همواره `ACTIVE`** است (تضاد با مقدار `PENDING` در blueprint برطرف شد).\n- این در §۱۲ [user-service.md](../../backend/services/user-service.md) تثبیت شد."
    },
    {
      "level": 3,
      "heading": "D8. پالیسی تغییر Username → IAM Policy Engine",
      "content": "- محدودیت‌های تغییر Username (`max_changes_per_year`, `cooldown_days`, `minimum_account_age`) توسط **IAM Policy Engine** تعریف و اعمال می‌شوند.\n- user-service صرفاً نتیجه بررسی پالیسی IAM را اجرا می‌کند و هیچ محدودیتی را هاردکد نمی‌کند.\n- این در §۱۶ و §۱۸ [user-service.md](../../backend/services/user-service.md) تثبیت شد."
    },
    {
      "level": 3,
      "heading": "D9. پالیسی تغییر Avatar → IAM",
      "content": "- همین سیاست (cooldown، rate_limit، quota) برای تغییر Avatar نیز توسط IAM اعمال می‌شود (ر.ک. §۱۸ [user-service.md](../../backend/services/user-service.md))."
    },
    {
      "level": 3,
      "heading": "D10. رویدادهای دامنه (Domain Events)",
      "content": "- رویداد اختصاصی **`nons.user.username.changed`** برای تغییر Username معرفی شد (مشتریان: search-service, notification-service, activity-service, audit-service).\n- رویداد `nons.user.profile.changed` دیگر فیلد `username` را در `changed_fields` منتشر نمی‌کند — جلوگیری از انتشار دوگانه (نقض قانون ۵).\n- ثبت در [events.yaml](../../../catalog/events/user/events.yaml) و [nons.user.username.changed.md](../../../catalog/events/user/nons.user.username.changed.md)."
    },
    {
      "level": 3,
      "heading": "D11. Pool به عنوان Shared Service",
      "content": "Pool Service توسط چندین سرویس مصرف می‌شود:\n- **user-service:** مواد تولید Username + متادیتای Avatar.\n- **currency-service:** Reference Data ارز (ISO 4217, نام، نماد، precision، country mapping) — ر.ک. C9.\n- **storage-service (آینده):** مهاجرت فایل‌های فیزیکی آواتار از Pool به Storage.\n\n---"
    },
    {
      "level": 2,
      "heading": "اصلاحات نسبت به پیش‌نویس اولیه (Scope Modifications)",
      "content": "> این اصلاحات توسط مالک در تایید اولیه اعمال شدند:\n\n- **C8 (Storage):** در MVP فایل‌های فیزیکی آواتار موقتاً در Pool Service ذخیره می‌شوند؛ در blueprint Pool به صراحت یادداشت مهاجرت به Storage Service در فاز بعدی آورده شد.\n- **C9 (Currency):** مرز صریح — Pool مالک Reference Data ارز، Currency Service مالک نرخ زنده (live rate / historical).\n- **C13 (Task):** تسک token-service پایان یافته است؛ در این فاز فقط مستندات به‌روزرسانی می‌شوند، سپس این ADR، و سپس تسک‌های جدید تعریف می‌شوند. هیچ تسک جدیدی فعلاً ایجاد نمی‌شود.\n\n---"
    },
    {
      "level": 2,
      "heading": "پیامدها (Consequences)",
      "content": ""
    },
    {
      "level": 3,
      "heading": "پیامدهای مثبت (Positive)",
      "content": "- **Single Source of Truth:** Reference Data و مواد تولید در یک نقطه متمرکز و قابل‌حکمرانی هستند.\n- **حکمرانی ادمین:** ادمین می‌تواند لیست کلمات و نام‌های رزرو شده را بدون deploy تغییر دهد.\n- **رفع تضاد Onboarding/Status:** مرز مسئولیت بین user-service و IAM صریح شد.\n- **عدم انتشار دوگانه:** قانون ۵ رعایت شد.\n- **قابلیت مقیاس‌پذیری:** سایر سرویس‌ها (currency, storage) می‌توانند از Pool بهره ببرند."
    },
    {
      "level": 3,
      "heading": "پیامدهای منفی (Negative)",
      "content": "- **هزینه ایجاد سرویس جدید:** Pool Service زیرساخت و نگهداری جدید دارد.\n- **وابستگی runtime:** user-service برای تولید Username به Pool Service وابسته می‌شود (نیاز به fallback محلی در Consumer برای resilience).\n- **کار migration کد:** حذف آرایه‌های hardcoded از `service.go` و seedهای آواتار از `migrations/001_init.sql` به فاز کد موکول شد (طبق C13).\n\n---"
    },
    {
      "level": 2,
      "heading": "منابع (References)",
      "content": "- [user-service.md](../../backend/services/user-service.md) — §۶/§۷/§۱۲/§۱۳/§۱۵/§۱۶/§۱۸ (تثبیت D2/D6/D7/D8/D9/D10)\n- [pool-service/blueprint.md](../../backend/services/pool-service/blueprint.md) — تعریف کامل سرویس (D1/D3/D4/D11)\n- [pool-service/README.md](../../backend/services/pool-service/README.md)\n- [iam-service.md](../../backend/services/iam-service.md) — مالکیت پالیسی و Onboarding (D6/D8/D9)\n- [currency-service.md](../../backend/services/currency-service.md) — مرز Reference Data (C9)\n- [events.yaml](../../../catalog/events/user/events.yaml) — تعریف رویدادها (D10)\n- [ADR-EVENT-001](./ADR-EVENT-001) — قرارداد نام‌گذاری رویدادها (`nons.<domain>.<entity>.<action>`)"
    }
  ]
}