{
  "title": "تصمیم معماری: استراتژی Metadata جنریتور و معماری Template-per-Framework",
  "slug": "team/platform/ADR/ADR-Platform-005",
  "url": "/docs/team/platform/ADR/ADR-Platform-005",
  "frontmatter": {
    "layout": "doc",
    "title": "'ADR-Platform-005: معماری Generator Metadata و استراتژی Template-per-Framework'",
    "description": "Architectural Decision Record defining the three-layer metadata model for CLI generator configuration and the template-per-framework architecture for client artifact generation.",
    "version": "1.0.0",
    "status": "APPROVED",
    "author": "Platform Team",
    "owner": "Platform Team",
    "created_at": "2026-07-04",
    "updated_at": "2026-07-04",
    "tags": "",
    "reviewers": ""
  },
  "sections": [
    {
      "level": 1,
      "heading": "تصمیم معماری: استراتژی Metadata جنریتور و معماری Template-per-Framework",
      "content": "**Architectural Decision Record — Generator Metadata Strategy & Framework Template Architecture**\n\n> **ADR-Platform-005 — Approved (Rev. 1.0)**\n\n---"
    },
    {
      "level": 2,
      "heading": "وضعیت (Status)",
      "content": "APPROVED (تایید شده)\n\n---"
    },
    {
      "level": 2,
      "heading": "تاریخ (Date)",
      "content": "2026-07-04\n\n---"
    },
    {
      "level": 2,
      "heading": "زمینه (Context)",
      "content": "پس از اجرای [ADR-Platform-004](./ADR-Platform-004) و تحلیل پیاده‌سازی اولیه جنریتور TypeScript در `cli/internal/generator/typescript/typescript.go`، دو ضعف معماری شناسایی شد:\n\n۱. **وابستگی runtime/framework داخل جنریتور:** مقدار hardcoded `process.env.NEXT_PUBLIC_API_URL` در تمام فریم‌ورک‌ها استفاده می‌شد، حتی اگر پروژه مصرف‌کننده Vue یا Vite باشد.\n\n۲. **سیاست transport جهانی و غیرقابل تنظیم:** `credentials: 'include'` بدون توجه به سرویس یا deployment بر تمام requestها اعمال می‌شد.\n\n۳. **منطق شاخه‌ای فریم‌ورک‌ها درون یک فایل واحد:** افزودن فریم‌ورک جدید نیازمند تغییر در `typescript.go` و تمام شاخه‌های موجود بود.\n\nاین ADR تصمیمات معماری را برای رفع این ضعف‌ها به شکل پایدار و قابل‌مقیاس تثبیت می‌کند.\n\n---"
    },
    {
      "level": 2,
      "heading": "تصمیمات مصوب (Decisions)",
      "content": ""
    },
    {
      "level": 3,
      "heading": "۱. مدل سه‌لایه Metadata (Three-Layer Metadata Model)",
      "content": "پیکربندی جنریتور از سه لایه مستقل تأمین می‌شود:\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│  لایه ۱: OpenAPI + x-nons Extensions                               │\n│  مالک: بک‌اند — اطلاعات per-operation، ذاتی سرویس                 │\n│                                                                     │\n│  • auth: true/false            • timeout                            │\n│  • content-type                • retry                              │\n│  • visibility (public/private) • cache config                       │\n│  • token name                  • rate-limit hints                   │\n└──────────────────────────────┬──────────────────────────────────────┘\n                               │ builder.go استخراج می‌کند\n┌──────────────────────────────▼──────────────────────────────────────┐\n│  لایه ۲: Service Manifest JSON                                      │\n│  مالک: CLI — snapshot خنثی transport، سطح سرویس                   │\n│                                                                     │\n│  • تمام داده‌های لایه ۱ (normalizeشده)                              │\n│  • auth_strategies: [\"BearerJWT\", \"CookieSession\"]                 │\n│  • transport.credentials_required: true/false                       │\n│  • transport.accept: \"application/json\"                             │\n│  • base_url (از OpenAPI servers[])                                  │\n└──────────────────────────────┬──────────────────────────────────────┘\n                               │ جنریتور می‌خواند\n┌──────────────────────────────▼──────────────────────────────────────┐\n│  لایه ۳: Consumer Config Overlay (.nons/config.yaml)               │\n│  مالک: مصرف‌کننده — deployment-specific، framework-specific        │\n│                                                                     │\n│  • transport.base_url_env: NEXT_PUBLIC_API_URL                      │\n│  • transport.credentials: include | omit | same-origin              │\n│  • framework: react | vue | next | nuxt | angular | svelte          │\n│  • output paths                                                     │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n**قانون جریان یک‌طرفه:** اطلاعات فقط از لایه بالاتر به لایه پایین‌تر جریان دارد. بک‌اند هرگز نام فریم‌ورک مصرف‌کننده را نمی‌داند.\n\n---"
    },
    {
      "level": 3,
      "heading": "۲. تفکیک مسئولیت منبع حقیقت",
      "content": "| دسته پیکربندی | منبع حقیقت | دلیل |\n|-------------|-----------|------|\n| مسیرها و متدهای API | OpenAPI | بک‌اند مالک تعریف مسیرهاست |\n| Schema درخواست/پاسخ | OpenAPI | بک‌اند مالک مدل داده است |\n| نیاز به auth | OpenAPI `security` + `x-nons.visibility` | بک‌اند می‌داند کدام endpoint احراز هویت نیاز دارد |\n| Content-Type هر درخواست | OpenAPI `requestBody` | بک‌اند فرمت مورد انتظار را تعریف می‌کند |\n| Timeout / retry / cache | OpenAPI `x-nons` | بک‌اند اطلاعات SLA هر operation را دارد |\n| Base URL تولید | OpenAPI `servers[]` | بک‌اند URL خود را می‌داند |\n| **نام env var** (`NEXT_PUBLIC_API_URL`) | **config.yaml** | وابسته به فریم‌ورک — بک‌اند نمی‌تواند بداند |\n| **حالت credentials** | **config.yaml** | وابسته به CORS policy deployment |\n| **الگوی Hook** (useState vs ref) | **config.yaml** + template | تصمیم فریم‌ورک فرانت‌اند |\n| **ساختار دایرکتوری خروجی** | **config.yaml** | قرارداد پروژه مصرف‌کننده |\n\n---"
    },
    {
      "level": 3,
      "heading": "۳. معماری Template-per-Framework",
      "content": "جنریتور از یک فایل واحد با شاخه‌بندی شرطی به معماری template-per-framework تبدیل می‌شود:\n\n```\nOpenAPI\n    ↓\nManifest (language-neutral)\n    ↓\nCore Generator (framework-agnostic)\n    ↓\nRenderContext (fully computed)\n    ↓\nTemplate Renderer\n    ├── react/\n    ├── next/\n    ├── vue/\n    ├── nuxt/\n    ├── angular/\n    └── (future: svelte/, solid/, node/, ...)\n```\n\n---"
    },
    {
      "level": 3,
      "heading": "۴. مرز مسئولیت Core Generator و Templates",
      "content": ""
    },
    {
      "level": 4,
      "heading": "Core Generator مسئول است:",
      "content": "- parse کردن `manifest.json`\n- resolve کردن operation token → function name\n- استنتاج path parameters از path strings\n- طبقه‌بندی operationها: GET/non-GET، auto-execute/manual\n- ساخت argument list تایپ‌دار از manifest params\n- تبدیل schema types → target language types\n- Reserved keyword safety enforcement\n- Sort deterministic operationها\n- Render کردن templates با RenderContext\n- نوشتن فایل‌های خروجی\n- Emit کردن هدر GENERATED"
    },
    {
      "level": 4,
      "heading": "Templates مسئول هستند:",
      "content": "- Import statements (react vs vue vs angular)\n- الگوی state management (useState vs ref vs signals)\n- الگوی effect/lifecycle (useEffect vs watch vs ngOnInit)\n- نام env var (NEXT_PUBLIC_API_URL vs VITE_API_URL)\n- نام دایرکتوری خروجی (hooks/ vs composables/ vs services/)\n- قرارداد نامگذاری فایل\n- سیستم module (import/export)\n\n**قانون تفکیک:** Templates فقط یک `RenderContext` از پیش‌محاسبه‌شده را render می‌کنند. Templates منطق ندارند — فقط rendering دارند.\n\n---"
    },
    {
      "level": 3,
      "heading": "۵. قرارداد RenderContext",
      "content": "RenderContext ساختار داده‌ای است که Core Generator محاسبه می‌کند و به templates می‌دهد:\n\n```go\ntype RenderContext struct {\n    ServiceName string\n    Operations  []OperationContext\n    Types       []TypeContext\n    Imports     []string\n    Config      TransportConfig\n}\n\ntype OperationContext struct {\n    FuncName       string   // computed از getFunctionName\n    HookName       string   // use{FuncName}\n    Method         string\n    Path           string\n    TemplatedPath  string   // برای template literals\n    PathParams     []string\n    QueryParams    []ParamInfo\n    HasRequestBody bool\n    RequestType    string\n    ResponseType   string\n    IsAuthRequired bool\n    AutoExecute    bool     // computed از shouldAutoExecute\n    IsFormEncoded  bool\n    ContentType    string\n}\n\ntype TransportConfig struct {\n    Framework   string\n    BaseURLEnv  string   // از config.yaml\n    Credentials string   // از config.yaml یا manifest\n}\n```\n\n---"
    },
    {
      "level": 3,
      "heading": "۶. پیکربندی Transport در config.yaml",
      "content": "بلوک `transport` به `config.yaml` اضافه می‌شود:\n\n```yaml\nproject:\n  name: my-app\n  framework: react    # react | vue | next | nuxt | angular | svelte | node\n  version: 1.0.0\n\npaths:\n  registry: .nons/registry\n  bundles: .nons/bundles\n  output: .nons/generated\n\ntransport:\n  base_url_env: NEXT_PUBLIC_API_URL    # نام env var فریم‌ورک\n  credentials: include                  # include | omit | same-origin\n  default_timeout: 10000               # ms — fallback اگر x-nons.timeout نباشد\n```\n\n**مقادیر پیش‌فرض فریم‌ورک** (اگر `transport` در config.yaml تعریف نشده باشد):\n\n| فریم‌ورک | `base_url_env` پیش‌فرض | `credentials` پیش‌فرض |\n|---------|----------------------|---------------------|\n| `next` | `NEXT_PUBLIC_API_URL` | `include` |\n| `react` | `REACT_APP_API_URL` | `omit` |\n| `vue` | `VITE_API_URL` | `omit` |\n| `nuxt` | `NUXT_PUBLIC_API_URL` | `include` |\n| `angular` | `API_URL` | `omit` |\n| `svelte` | `VITE_API_URL` | `omit` |\n| `node` | `API_URL` | `omit` |\n\n---"
    },
    {
      "level": 3,
      "heading": "۷. شش اصل تضمینی (Six Invariants)",
      "content": "این اصول در تمام پیاده‌سازی‌های آینده باید رعایت شوند:\n\n1. **Backend هیچوقت نام framework ندارد در spec.** هیچ `x-nons.framework`، هیچ `x-nons.react_*`. بک‌اند نمی‌داند چه کسی مصرف‌کننده آن است.\n\n2. **Core Generator هیچ string خاص framework ندارد.** هیچ `\"vue\"`, `\"react\"`, `\"NEXT_PUBLIC\"` در `generator.go` یا کد اصلی generation. این‌ها به templates و config تعلق دارند.\n\n3. **Templates فقط render می‌کنند — بدون business logic.** هیچ type resolution، هیچ path parsing، هیچ auth detection. Templates فقط RenderContext از پیش‌محاسبه‌شده را render می‌کنند.\n\n4. **config.yaml همیشه optional با safe defaults است.** `nons generate` باید با حداقل config کار کند. پیش‌فرض‌های transport بر اساس `framework` از جدول بالا انتخاب می‌شوند.\n\n5. **Manifest کاملاً language-neutral است.** هیچ فیلد TypeScript-specific در manifest. Manifest باید به یک Kotlin generator، Dart generator، و TypeScript generator به یک اندازه مفید باشد.\n\n6. **Generator determinism یک invariant است.** خروجی identical برای manifest + config identical، همیشه. تمام عملیات روی map قبل از rendering باید sort شوند.\n\n---"
    },
    {
      "level": 3,
      "heading": "۸. پشتیبانی از فریم‌ورک‌های آینده",
      "content": "| فریم‌ورک | نوع | تغییر Core Generator؟ |\n|---------|-----|----------------------|\n| Svelte 5 (runes) | Frontend SPA | ❌ خیر — فقط template جدید |\n| SolidJS | Frontend SPA | ❌ خیر — فقط template جدید |\n| Remix | SSR | ❌ خیر — فقط template جدید |\n| Astro | Static/SSR | ❌ خیر — فقط template جدید |\n| React Native | Mobile | ❌ خیر — فقط template جدید |\n| Node.js SDK | Server | ❌ خیر — فقط template جدید |\n| Flutter (Dart) | Mobile | ⚠ نیاز به Generator جدید (نه template) |\n| Android/Kotlin | Mobile | ⚠ نیاز به Generator جدید (نه template) |\n\nبرای targets غیر-TypeScript، `Generator interface` (`Generate(m *Manifest, outputDir string) error`) اکستنشن‌پوینت صحیح است.\n\n---"
    },
    {
      "level": 3,
      "heading": "۹. ارتباط با ADRهای قبلی",
      "content": "| ADR | ارتباط |\n|-----|--------|\n| [ADR-Platform-004](./ADR-Platform-004) | این ADR بر آن بنا شده — به جای جایگزینی، مکمل است |\n| [ADR-Platform-001](./ADR-Platform-001) | Manifest language-neutral از Proto pattern پیروی می‌کند |\n\n---"
    },
    {
      "level": 2,
      "heading": "پیامدها (Consequences)",
      "content": ""
    },
    {
      "level": 3,
      "heading": "پیامدهای مثبت (Positive)",
      "content": "- **Blast radius کمتر:** افزودن فریم‌ورک جدید، کد موجود را لمس نمی‌کند\n- **Ownership مستقل:** هر تیم می‌تواند template فریم‌ورک خود را مستقلاً داشته باشد\n- **قابلیت تست ایزوله:** هر template با یک fixture manifest به تنهایی تست می‌شود\n- **Backend-agnostic transport:** سرویس‌های مختلف deployment policy متفاوت می‌توانند داشته باشند\n- **آماده‌بودن برای فریم‌ورک‌های آینده:** بدون تغییر در core generator"
    },
    {
      "level": 3,
      "heading": "پیامدهای منفی (Negative)",
      "content": "- **هزینه migration:** refactor کردن `typescript.go` به ساختار template نیاز به کار دارد\n- **مستندسازی RenderContext:** قرارداد بین Core و Templates باید صریح و نگهداری‌شده باشد\n- **پیچیدگی اولیه:** ساختار چندفایله در ابتدا پیچیده‌تر از یک فایل واحد به نظر می‌رسد\n\n---"
    },
    {
      "level": 2,
      "heading": "منابع (References)",
      "content": "- [CLI-SDK-AUDIT-REPORT.md] — گزارش audit اولیه که ضعف‌های معماری را شناسایی کرد\n- [ARCH-VALIDATION-REPORT.md] — گزارش validation معماری که این تصمیمات از آن استخراج شد\n- [cli-reference.md](../package/cli-reference) — راهنمای کامل CLI\n- [nons-ContractManagement-guide.md](../package/nons-ContractManagement-guide) — راهنمای مدیریت قرارداد"
    }
  ]
}