راهنمای توسعه‌دهندگان پوشش

مستند زنده‌ی فنی پروژه

راهنمای توسعه‌دهندگان پوشش

مرجع سریع و خوانای معماری، زیرساخت و فرایندهای فنی Poshesh. هر فصل یک موضوع مستقل را از تصمیم‌های پایه تا اجرای عملی و چک‌لیست نهایی، کوتاه و مرحله‌به‌مرحله توضیح می‌دهد.

نسخه‌ی سند ۱.۳ به‌روزرسانی: ۱۴۰۵/۰۵/۲۴ ASP.NET Core MVC · .NET 10 fa-IR · RTL

از اینجا شروع کنید

فهرست مستندات

هر فصل مستقل است. برای یادگیری، بخش‌های هر فصل را به‌ترتیب بخوانید؛ برای مراجعه‌ی روزمره، مستقیم به موضوع موردنظر بروید.

فصل ۰

راهنمای سند

روش استاندارد افزودن فصل، بخش، کد و تصویر

فصل ۱

معماری و ساختار پروژه

پوشه‌ها، پروژه‌ها، وابستگی‌ها و مرزهای معماری

فصل ۲

دیپلوی و انتشار

ساخت خروجی، استقرار سایت و انتشار هسته، افزونه و قالب

فصل ۳

مدیریت محتوا

چارچوب صفحه، هدر و فوتر داینامیک، صفحه اصلی و اتصال آن‌ها به قالب و افزونه

فصل ۴

طراحی و اجرای ورک‌فلو

آموزش سادهٔ ساخت فرایند، اتصال گام‌ها، متغیرها، آزمایش، انتشار و پایش اجراها

فصل ۱ · بخش ۱

معماری در یک نگاه

Poshesh یک CMS و سایت‌ساز «پلتفرم‌محور» است؛ هسته‌ی نصب به‌تنهایی یک موتور کامل سایت است و امکانات اختیاری به‌شکل افزونه وارد می‌شوند.

اصل ساده: پایین‌دست، بالادست را نمی‌شناسد

قراردادهای عمومی در پایین‌ترین لایه قرار دارند. پیاده‌سازی‌ها و UI روی آن‌ها ساخته می‌شوند. نتیجه این است که هسته قابل‌استفاده می‌ماند و جزئیات وب، EF Core یا یک قابلیت خاص به قراردادهای پایه نشت نمی‌کند.

  • Framework ابزار و قرارداد مشترک می‌دهد.
  • Platform قابلیت‌های داخلی CMS را به‌صورت Vertical Slice نگه می‌دارد.
  • Host فقط برنامه را سرهم و اجرا می‌کند.
  • Plugin قابلیت اختیاری و مستقل است؛ Theme ظاهر عمومی را تعیین می‌کند.
Poshesh.Web Composition root / executable host
Poshesh.Platform Built-in vertical-slice features
Poshesh.Framework.Web MVC, security, theming, plugins
Poshesh.Framework.Infrastructure EF conventions, cache, jobs, storage
Poshesh.Framework.Core Contracts and primitives only

فصل ۱ · بخش ۲

نقشه‌ی پوشه‌های مخزن

این نقشه محل هر خانواده‌ی کد را نشان می‌دهد. پوشه‌های تولیدشده مانند bin و obj عمداً نمایش داده نشده‌اند.

repository-map.txt
YektaBrick/
├── src/
│   ├── Framework/
│   │   ├── Poshesh.Framework.Core
│   │   ├── Poshesh.Framework.Infrastructure
│   │   └── Poshesh.Framework.Web
│   ├── Platform/
│   │   └── Poshesh.Platform
│   ├── Host/
│   │   └── Poshesh.Web
│   └── AppHost/
│       ├── Poshesh.AppHost
│       └── Poshesh.ServiceDefaults
├── plugins/                 # افزونه‌های مستقل و نمونه
├── themes/                  # قالب‌ها؛ هر قالب یک پروژه‌ی ماژولی مثل افزونه
├── tests/                   # تست‌های واحد و مرزهای معماری
├── tools/                   # ابزارهای اجرایی مانند Updater
├── versioning/              # زیرسامانه‌ی جداگانه‌ی انتشار و مجوز
├── docs/                    # ADR و قراردادهای فنی تفصیلی
├── learn/                   # همین راهنمای ساده‌ی توسعه‌دهندگان
├── eng/                     # اسکریپت‌های مهندسی، build و publish
├── artifacts/               # خروجی توسعه و کشف افزونه‌ها
├── Published/               # خروجی نهایی قابل‌تحویل؛ git-ignored
├── Poshesh.sln              # Solution اصلی برنامه
├── Directory.Build.props    # قواعد مشترک MSBuild
├── Directory.Packages.props # نسخه‌های مرکزی NuGet
├── global.json              # تثبیت خانواده‌ی .NET SDK 10
├── AGENTS.md                # راهنمای Codex و جلسات آینده
└── CLAUDE.md                # راهنمای Claude Code
پوشهچه چیزی داخل آن است؟قاعده‌ی استفاده
src/کد اصلی Framework، Platform، Host و Aspireهر کد پایه‌ی محصول از اینجا شروع می‌شود.
plugins/قابلیت‌های اختیاری با چرخه‌ی عمر و در صورت نیاز DbContext مستقلوابستگی به قابلیت‌های Platform ممنوع؛ ارتباط از قراردادهای Framework است.
themes/پروژه‌ی هر قالب (manifest + اسمبلی + ویوها)ظاهر سایت عمومی را تغییر می‌دهد و می‌تواند کنترلر، سرویس و ویجت هم داشته باشد؛ پنل ادمین قالب ثابت خود را دارد.
docs/قراردادهای دقیق، ADRها و جزئیات زیرسیستم‌هامرجع عمیق فنی؛ این فایل خلاصه‌ی قابل‌خواندن آن‌هاست.
learn/راهنمای یک‌صفحه‌ای توسعه‌دهندگانفقط با درخواست صریح کاربر ویرایش می‌شود.
versioning/API و پنل تحت وب انتشار، مجوز و بسته‌های نسخهزیرسامانه‌ای مستقل از Solution اصلی با مرز استقرار جدا است.
artifacts/خروجی‌های موقت توسعه، از جمله افزونه‌های قابل کشفمحل تحویل محصول نیست.
Published/خروجی Release سایت، افزونه، قالب و بسته‌های zipتنها محل فایل‌های قابل‌تحویل به سرور یا مشتری است.

فصل ۱ · بخش ۳

مسئولیت هر پروژه

نام پروژه به‌تنهایی کافی نیست. این فهرست می‌گوید هر پروژه چه کاری انجام می‌دهد و چه چیزی نباید وارد آن شود.

Poshesh.Framework.Core

BASE

قراردادها، primitiveها، مدل‌های مشترک، Result، eventها، permissionها و extension pointهای عمومی.

مرز: بدون EF Core و بدون ASP.NET Core. همه می‌توانند به آن وابسته باشند؛ خودش به جزئیات وابسته نیست.

Poshesh.Framework.Infrastructure

INFRA

پیاده‌سازی زیرساخت مشترک: convention و interceptorهای EF، cache، job، storage، audit، secret و update client.

وابستگی: فقط روی Core ساخته می‌شود. منطق یک قابلیت CMS در این پروژه قرار نمی‌گیرد.

Poshesh.Framework.Web

WEB

چسب MVC و HTTP: pipeline، امنیت، theme engine، plugin loader، view location، assetها، panelها و widget pipeline.

وابستگی: Infrastructure و در نتیجه Core. هیچ feature داخلی Platform را نمی‌شناسد.

Poshesh.Platform

RCL

تمام قابلیت‌های داخلی CMS در Features/*، به‌همراه PlatformDbContext، migrationها، viewها و assetهای پنل.

قاعده: هر قابلیت یک Vertical Slice مستقل است؛ ارجاع مستقیم بین namespaceهای قابلیت‌ها ممنوع است.

Poshesh.Web

HOST

Composition root و برنامه‌ی قابل اجرا. تنظیمات، Program.cs، نسخه‌ی سایت و فایل‌های میزبان اینجاست. Host به هیچ افزونه یا قالبی ارجاع ندارد؛ هر دو در زمان اجرا کشف و بارگذاری می‌شوند.

قاعده: نازک بماند؛ منطق دامنه یا feature داخل Host نوشته نمی‌شود.

Poshesh.AppHost

ASPIRE

ارکستریشن توسعه با .NET Aspire؛ اجرای راحت Host و منابعی مانند SQL Server.

نکته: ابزار توسعه است. سایت باید بدون AppHost هم اجرا و deploy شود.

Poshesh.ServiceDefaults

OBSERVE

پیش‌فرض‌های مشترک OpenTelemetry، health check و resilience برای سرویس‌های اجرایی.

مصرف‌کننده: Host آن را ثبت می‌کند؛ AppHost اجرای محلی را هماهنگ می‌کند.

Poshesh.Theme.Default

THEME

قالب عمومی پیش‌فرض به‌شکل یک ماژول کامل: manifest، اسمبلی ورودی، ویوها، ویجت، تنظیمات و کنترلر خودش، ترجمه‌ها و wwwroot.

مرز: به Framework.Web ارجاع دارد، نه Platform. مدل قابل override باید در Framework قابل دسترس باشد.

Poshesh.Tests

VERIFY

تست‌های واحد و NetArchTest برای قفل‌کردن مرزهای معماری، به‌ویژه استقلال featureها.

قاعده‌ی فعلی: تا فاز نهایی تست جدید اضافه نمی‌شود، مگر با درخواست کاربر.

Poshesh.Updater

TOOL

ابزار مستقل و کم‌وابستگی برای اعمال آفلاین بسته‌ی به‌روزرسانی و راه‌اندازی دوباره‌ی سایت.

خروجی: همراه سایت در مسیر updater منتشر می‌شود، اما عضو لایه‌های runtime وب نیست.

افزونه‌های موجود

پروژهنقشوابستگی مستقیم
Poshesh.Plugin.HelloWorldنمونه‌ی کوچک مجوز، منوی پنل، تنظیمات و hookFramework.Web
Poshesh.Plugin.Projectsنمونه‌ی افزونه‌ی داده‌دار با DbContext و migration مستقل، widget و APIFramework.Web + Infrastructure
Poshesh.Plugin.Shop.Contractsقرارداد مشترک فروشگاه برای Theme و افزونه‌های satellite؛ بدون EF/ASP.NET/Coreبدون ProjectReference داخلی
Poshesh.Plugin.Shopماژول نمونه‌ی فروشگاه و مالک قراردادهای اجرایی آنFramework.Web + Shop.Contracts
Poshesh.Plugin.Shop.TestPayدرگاه آزمایشی satellite برای ShopFramework.Web + Shop.Contracts

زیرسامانه‌ی مستقل Versioning

Versioning.Api

SERVICE

سرویس جداگانه‌ی انتشار نسخه، ثبت سایت، مجوز، heartbeat، بسته‌های به‌روزرسانی و امضای آن‌ها.

استقرار: جدا از سایت مشتری و با دیتابیس و storage مستقل اجرا می‌شود.

versioning/panel

NEXT.JS

پنل تحت وب اپراتور برای مدیریت Versioning API: انتشار بسته‌ها، سایت‌ها، لایسنس، مخزن افزونه و تنظیمات سرویس.

مرز: کلاینت مدیریتی سرویس Versioning است؛ بخشی از پنل ادمین وب Poshesh نیست.

Versioning.Panel

WINFORMS · قدیمی

پنل ویندوزی پیشین همان سرویس. جای خود را به پنل تحت وب داده و برای کارهای روزمره استفاده نمی‌شود.

مرز: فقط برای مراجعه؛ مسیر انتشار پشتیبانی‌شده، پنل تحت وب است.

فصل ۱ · بخش ۴

وابستگی پروژه‌ها

فلش یعنی «پروژه‌ی سمت راست به پروژه‌ی سمت چپ ارجاع دارد». مسیر اصلی یک‌طرفه و قابل پیش‌بینی است.

Framework.Core
←
Framework.Infrastructure
Framework.Infrastructure
←
Framework.Web
Framework.Web
←
Platform
Platform + ServiceDefaults + DefaultTheme
←
Host / Poshesh.Web
Poshesh.Web
←
Poshesh.AppHost

Composition قطعی و بدون حدس

کد داخلی Platform با assembly scanning پیدا نمی‌شود. Host به‌صورت صریح Framework، Platform و Theme را ثبت می‌کند؛ خود Platform نیز فهرست ثابت و مرتب‌شده‌ی registrarها را اجرا می‌کند.

src/Host/Poshesh.Web/Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();
builder.AddPoshesh().AddPlatform();
builder.Services.AddDefaultTheme();

var app = builder.Build();

app.UsePoshesh();
app.MapDefaultEndpoints();
app.Run();

فصل ۱ · بخش ۵

مسیر اجرای برنامه و یک درخواست

این مسیر، جای هر مسئولیت را در زمان startup و هنگام رسیدن درخواست HTTP نشان می‌دهد.

۱

Host تنظیمات را می‌خواند

Poshesh.Web محیط، appsettings، نسخه و سرویس‌های مشترک را آماده می‌کند.

۲

Framework ثبت می‌شود

AddPoshesh() زیرساخت، MVC، امنیت، localization، theme engine، plugin runtime و قراردادهای عمومی را متصل می‌کند.

۳

Platform قابلیت‌ها را ثبت می‌کند

AddPlatform() در صورت وجود connection string، DbContext را ثبت و registrarهای ثابت featureها را به‌ترتیب اجرا می‌کند.

۴

Registryها یک‌بار ساخته می‌شوند

Permission، menu، theme، widget، post type و سایر providerها در startup جمع و سپس immutable می‌شوند.

۵

Pipeline فعال می‌شود

UsePoshesh() middlewareهای امنیت، culture، routing، audit context، static assets و endpointها را با ترتیب ثابت می‌چیند.

۶

درخواست به feature درست می‌رسد

Controller یا content route handler درخواست را می‌گیرد؛ permission و antiforgery در مرز وب بررسی می‌شوند.

۷

Service کار را انجام می‌دهد

Command service از Result استفاده می‌کند؛ query service با AsNoTracking() مدل خواندن را می‌سازد. DbContext همان Unit of Work است.

۸

Theme یا View پاسخ را رندر می‌کند

پنل ادمین از پوسته‌ی ثابت Velzon استفاده می‌کند. سایت عمومی از زنجیره‌ی active theme → parent → feature → platform view می‌گیرد.

فصل ۱ · بخش ۶

داخل Poshesh.Platform

Platform یک پروژه است، اما ساختار داخلی آن feature-first است. هر قابلیت، فایل‌های دامنه تا UI خودش را کنار هم نگه می‌دارد.

Features/{FeatureName}/
Features/Example/
├── Domain/                 # Entity، value object و EF configuration
├── Services/               # command/query service و پیاده‌سازی منطق
├── Controllers/            # endpointهای MVC؛ معمولاً Area ادمین
├── Models/                 # view model، input model و projection
├── Views/                  # Razor viewهای همان قابلیت
├── Permissions.cs          # نام permissionهای پایدار
├── ExamplePermissionProvider.cs
├── ExampleAdminMenuProvider.cs
└── Registrar.cs            # ثبت صریح سرویس‌های این slice

پوشه‌ها می‌توانند بر اساس نیاز feature کمتر یا بیشتر باشند؛ اصل مهم این است که فایل‌های یک قابلیت کنار هم بمانند و برای همکاری با قابلیت دیگر از قرارداد مشترک عبور کنند.

هسته و مدیریت

AdminApiIdentityInstallerPanelsSettingsSystemUpdateAudit

محتوا و تجربه

HomePagesPostsPageBuilderWidgetsEditorMediaMenusTaxonomy

سرویس‌های مشترک سایت

FormsGeoLocalizationNotificationsSeoThemesPlugins

فصل ۱ · بخش ۷

مرزهای معماری که نباید شکسته شوند

این قواعد سلیقه‌ای نیستند؛ بخشی از آن‌ها با NetArchTest کنترل می‌شوند و بخش دیگر قرارداد پایدار توسعه‌ی پروژه‌اند.

  • Feature به Feature ارجاع نمی‌دهد. مثلاً Posts نباید namespace یا entity مربوط به Taxonomy را مستقیماً مصرف کند.
  • همکاری بین featureها از Framework می‌گذرد. قرارداد، event، registry یا سرویس feature-neutral راه ارتباط است.
  • Composition تنها جای شناخت همه‌ی featureهاست. فهرست registrarها در Platform/Composition صریح و مرتب است.
  • Host نازک می‌ماند. Host محل business rule، query یا entity جدید نیست.
  • Core از جزئیات آزاد است. ASP.NET Core، EF Core و typeهای Platform وارد قراردادهای Core نمی‌شوند.
  • DbContext همان Unit of Work است. generic repository و UnitOfWork wrapper عمومی ساخته نمی‌شود.
  • شناسه‌ها Guid v7 هستند. entity شناسه را سمت client و پیش از insert می‌سازد.
  • Theme فقط قرارداد قابل‌دسترسی خود را می‌بیند. مدلی که قالب عمومی نیاز دارد باید در Framework قرار بگیرد، نه namespace یک feature.
cross-feature-collaboration.cs
// نادرست: وابستگی مستقیم به slice دیگر
using Poshesh.Platform.Features.Taxonomy.Domain;

// درست: قرارداد feature-neutral در Framework.Core
public sealed class PostService(IContentTaxonomyService taxonomy)
{
    // همکاری از مرز عمومی و پایدار انجام می‌شود.
}

فصل ۱ · بخش ۸

کد جدید کجا قرار می‌گیرد؟

پیش از ساخت پوشه یا پروژه‌ی تازه، نوع تغییر را مشخص کنید. این جدول مسیر معمول را نشان می‌دهد.

قرارداد عمومی یا primitive
Framework.Core؛ فقط وقتی چند مصرف‌کننده به یک مرز پایدار نیاز دارند.
پیاده‌سازی مشترک غیر وب
Framework.Infrastructure؛ مانند cache، storage، background job یا convention دیتابیس.
رفتار عمومی MVC/HTTP
Framework.Web؛ مانند middleware، TagHelper، theme/plugin glue یا asset resolver.
قابلیت پایه‌ی خود CMS
یک slice در Platform/Features/{Name} و ثبت صریح registrar آن در composition.
قابلیت اختیاری یا پروژه‌ای
یک پروژه در plugins/؛ اگر داده دارد با DbContext و migration مستقل.
تغییر ظاهر سایت عمومی
در themes/: یک پروژه‌ی قالب بسازید یا ویوی موردنظر را در قالب فعال override کنید (docs/themes.md).
تنظیم startup یا میزبانی
Poshesh.Web؛ فقط composition و configuration، نه business logic.
ابزار انتشار/نگهداری مستقل
tools/ یا زیرسامانه‌ای با مرز استقرار روشن؛ ساخت پروژه‌ی تازه باید تصمیم معماری باشد.

فصل ۲ · بخش ۱

نقشه‌ی صحیح دیپلوی و انتشار

در Poshesh «ساخت خروجی»، «دیپلوی اولیه» و «انتشار نسخه» سه کار مرتبط اما متفاوت‌اند. نقطه‌ی مشترک همه‌ی آن‌ها پوشه‌ی Published است.

۱

نسخه‌ها را در سورس مشخص کنید

نسخه‌ی هسته در version.json و نسخه‌ی افزونه یا قالب در manifest همان بسته قرار دارد.

۲

خروجی Release بسازید

eng/publish.ps1 سایت، Updater، افزونه‌ها و قالب‌ها را پاک‌سازی و بسته‌بندی می‌کند و قالب‌ها را در خروجی سرور پیش‌نصب می‌گذارد.

۳

خروجی درست را انتخاب کنید

Published/App برای سرور؛ ZIP هسته برای Versioning؛ ZIP افزونه و قالب برای مخزن افزونه‌هاست.

۴

دیپلوی یا انتشار کنید

سرور تازه فایل‌های App را می‌گیرد. نسخه‌های قابل به‌روزرسانی با آپلود ZIP در پنل تحت وب منتشر و امضا می‌شوند.

۵

نسخه‌ی منتشرشده را راستی‌آزمایی کنید

شماره نسخه، کانال، وضعیت فعال، وجود فایل بسته و پاسخ سایت پس از نصب را کنترل کنید.

کارورودی صحیحمقصد
Initial deploymentPublished/Appریشه‌ی برنامه روی سرور مشتری
Core updatePublished/poshesh-{version}.zip آپلودشده در پنلVersioning service → سایت‌های متصل
Plugin releasePublished/Plugins/{id}-{version}.zipمخزن افزونه و قالب در Versioning
Theme releasePublished/Themes/{id}-{version}.zipمخزن افزونه و قالب در Versioning

فصل ۲ · بخش ۲

اجرای اسکریپت انتشار

اسکریپت را از ریشه‌ی مخزن و با PowerShell 7 اجرا کنید. اجرای بدون پارامتر همه‌ی خروجی‌ها را با تنظیم Release می‌سازد.

PowerShell 7 — repository root
cd D:\Github.com\YektaBrick
pwsh -File .\eng\publish.ps1

اگر ExecutionPolicy جلوی اجرای اسکریپت را گرفت، فقط برای همین پردازش از دستور زیر استفاده کنید:

ExecutionPolicy fallback
pwsh -ExecutionPolicy Bypass -File .\eng\publish.ps1

نمونه‌های کاربردی

publish-examples.ps1
.\eng\publish.ps1                         # همه خروجی‌ها با نسخه فعلی
.\eng\publish.ps1 -Version 1.0.0          # ثبت نسخه هسته و ساخت همه خروجی‌ها
.\eng\publish.ps1 -Target App             # فقط سایت، Updater و ZIP هسته
.\eng\publish.ps1 -Target Plugins         # همه افزونه‌های دارای plugin.json
.\eng\publish.ps1 -Target Themes -NoZip   # فقط پوشه قالب‌ها، بدون ZIP

فصل ۲ · بخش ۳

پارامترها و کاربرد صحیح آن‌ها

مقادیر پیش‌فرض برای خروجی مشتری امن هستند. پارامترهای غیر Release فقط برای آزمایش محلی‌اند و نباید تحویل شوند.

پارامترپیش‌فرضکاربرد
-TargetAllAll، App، Plugins یا Themes. فقط خانواده‌ی انتخاب‌شده ساخته می‌شود.
-Versionنسخه‌ی فعلیفقط در ساخت App مصرف می‌شود؛ version.json را پیش از publish بازنویسی و نام ZIP هسته را تعیین می‌کند.
-ProductCodeposheshنام محصول در manifest و نام ZIP هسته. معمولاً تغییر ندهید.
-Channelstableکانال manifest هسته: stable یا beta. کانال افزونه/قالب هنگام انتشار در پنل انتخاب می‌شود.
-NoZipخاموشZIP هسته، افزونه و قالب را نمی‌سازد و فقط پوشه‌های آماده را باقی می‌گذارد.
-ConfigurationReleaseتنظیم build. مقدار دیگر به‌طور پیش‌فرض رد می‌شود.
-AllowNonReleaseخاموشفقط برای آزمایش محلی؛ هرگز خروجی آن را به مشتری یا Versioning ندهید.

فصل ۲ · بخش ۴

ساختار خروجی Published

پس از پایان اسکریپت، summary پایانی مسیر دقیق خروجی‌های همین اجرا را نشان می‌دهد. فایل مناسب را از این ساختار بردارید.

Published/
Published/
├── App/                              # سایت دقیقاً به شکل قابل کپی روی سرور
│   ├── Poshesh.Web.exe
│   ├── version.json
│   ├── wwwroot/
│   └── updater/
│       └── Poshesh.Updater.exe       # برای update و restart الزامی
├── poshesh-1.0.0.zip                 # بسته قابل انتشار هسته
├── Plugins/
│   ├── projects/                     # پوشه آماده نصب؛ plugin.json در ریشه
│   └── projects-1.0.0.zip            # ZIP قابل آپلود در مخزن
└── Themes/
    ├── Sample/                       # قالب پوشه‌ای آماده؛ theme.json در ریشه
    └── Sample-1.0.0.zip              # ZIP قابل آپلود در مخزن
  • App یک server drop است. محتویات آن بدون ساخت دوباره روی سرور قرار می‌گیرد.
  • ZIP هسته manifest دارد. manifest.json فقط داخل آرشیو است و داخل App قرار نمی‌گیرد.
  • ZIP افزونه و قالب در ریشه manifest دارند. پوشه‌ی wrapper اضافه ساخته نمی‌شود.
  • Default Theme جداگانه منتشر نمی‌شود. قالب RCL پیش‌فرض در خروجی هسته‌ی سایت کامپایل شده است.
  • فایل‌های محلی حذف شده‌اند. appsettings.Local.json، appsettings.Development.json و PDB نباید در خروجی مشتری باشند.

فصل ۲ · بخش ۵

دیپلوی اولیه‌ی سایت روی سرور

برای نصب تازه، ZIP به‌روزرسانی را extract نکنید. خروجی صحیح، پوشه‌ی کامل Published/App است که Updater را نیز همراه دارد.

  1. ابتدا VSC را آماده کنید. سرویس Versioning باید با storage دائمی، دیتابیس و چهار کلید production بالا آمده باشد.
  2. اثر انگشت را کنترل کنید. پاسخ GET /api/public/info باید fingerprint مورد انتظار production را برگرداند.
  3. پس از تأیید VSC خروجی سایت را بسازید. برای نسخه‌ی مقصد، publish.ps1 -Version x.y.z -Target App را اجرا کنید.
  4. محتویات Published/App را به app root سرور منتقل کنید. وجود updater/Poshesh.Updater.exe را جداگانه بررسی کنید.
  5. برنامه را اجرا و Installer را کامل کنید. Installer اتصال دیتابیس، ثبت VSC و مدیر اولیه را انجام و appsettings.Local.json مخصوص همان سرور را می‌سازد.
  6. ورود و نسخه را بررسی کنید. صفحه‌ی عمومی، پنل ادمین و شماره نسخه‌ی نصب‌شده باید بدون خطا پاسخ دهند.
production trust fingerprint
5ABA6781481EABF9DF92E148921BCB78A75D1A901DB4DAA80200861DC7B00D8B

فصل ۲ · بخش ۶

انتشار نسخه‌ی جدید هسته

یک مسیر بیشتر نیست: با publish.ps1 بسته را بسازید و در پنل تحت وب آپلود کنید. سرویس هنگام آپلود manifest را بازنویسی می‌کند و فهرست فایل‌های حذف‌شده را خودش می‌سازد.

prepare-core-release.ps1
.\eng\publish.ps1 -Version 1.2.0 -Target App
git diff -- src\Host\Poshesh.Web\version.json

چه کاری کجا انجام می‌شود

مرحلهمجرینتیجه
نوشتن version.json و ساخت خروجی Releaseeng/publish.ps1Published/App و Published/poshesh-{version}.zip
inventory اولیه با SHA-256eng/publish.ps1manifest.json داخل ZIP با deleted خالی
مقایسه با نسخه‌ی قبلی و ساخت deletedسرویس، هنگام آپلودmanifest بازنویسی و جایگزین می‌شود
hash و امضای ECDSAسرویس، پس از بازنویسیامضا روی فایل نهایی، نه فایل آپلودشده

مراحل داخل پنل تحت وب

  1. خروجی را با publish.ps1 -Version بسازید و تغییر version.json را commit کنید.
  2. وارد پنل شوید و به صفحه‌ی «نسخه‌های سایت اصلی» بروید؛ «انتخاب ZIP و انتشار سایت» را بزنید.
  3. محصول را poshesh، نسخه را دقیقاً برابر version.json و کانال را stable یا beta بگذارید.
  4. فایل Published/poshesh-{version}.zip را انتخاب و توضیحات نسخه را کوتاه و کاربردی بنویسید.
  5. «بارگذاری و ثبت» را بزنید. پیام موفقیت تعداد فایل‌ها و تعداد فایل‌های حذف‌شده را گزارش می‌کند؛ همین عدد را کنترل کنید.
  6. در فهرست نسخه‌ها، وجود فایل بسته، کانال و وضعیت فعال را بررسی کنید. دکمه‌ی «محتوای بسته» فهرست فایل‌ها و حذف‌شده‌ها را نشان می‌دهد.

اعمال نسخه روی سایت

پس از فعال‌شدن release، مدیر سایت می‌تواند از /admin/system/update به‌روزرسانی را شروع کند. اپراتور مرکزی نیز در صفحه‌ی «سایت‌های نصب‌شده» یک سایت را انتخاب و «بروزرسانی از راه دور» را می‌زند؛ چند لحظه بعد «بررسی زنده» وضعیت بازگشت سایت را تأیید می‌کند.

فصل ۲ · بخش ۷

ساخت و انتشار افزونه

نسخه و هویت افزونه از plugin.json می‌آید. اسکریپت همه‌ی پوشه‌های دارای این manifest را publish و برای مخزن بسته‌بندی می‌کند.

  1. در plugin.json مقدارهای id و version را بررسی کنید. شناسه باید lower-case و با نام package و پوشه‌ی نصب دقیقاً یکسان باشد.
  2. مطمئن شوید entryAssembly یا DLL پیش‌فرض افزونه در خروجی وجود خواهد داشت و dependencyها درست‌اند.
  3. دستور زیر را اجرا و ZIP همان نسخه را از summary نهایی بردارید.
publish-plugins.ps1
.\eng\publish.ps1 -Target Plugins

# خروجی نمونه
Published\Plugins\projects\
Published\Plugins\projects-1.0.0.zip

انتشار از پنل تحت وب

  1. وارد «مخزن افزونه و قالب» شوید.
  2. اگر package هنوز وجود ندارد، «تعریف بسته و آپلود» را بزنید؛ نوع افزونه، شناسه‌ی canonical، نام، توضیح، دسته، حداقل پلن و وضعیت Listed/Featured را تعیین کنید. می‌توانید ZIP اولین نسخه را همان‌جا بدهید.
  3. اگر package قبلاً تعریف شده، آن را انتخاب و «نسخه جدید» را بزنید؛ مسیر دیگر «نسخه‌ها» → «انتشار نسخه جدید» است.
  4. شماره نسخه باید دقیقاً با plugin.json:version برابر باشد. کانال، توضیحات و ZIP ساخته‌شده را انتخاب و «آپلود و انتشار» را اجرا کنید.
  5. سرویس ساختار ZIP، identity، نسخه، dependency، entry assembly و محدودیت‌ها را بررسی می‌کند؛ سپس archive را hash و امضا و seal فایل‌های افزونه را داخل بسته ثبت می‌کند.

فصل ۲ · بخش ۸

ساخت قالب به‌عنوان ماژول

قالب و افزونه یک چیزند: پروژه، manifest، اسمبلی ورودی، load context مستقل. تفاوت فقط در نقش است — افزونه «کار سایت» را می‌سازد و قالب «ظاهر سایت» را، و قالب تنها ماژولی است که می‌تواند هر ویویی را در برنامه جایگزین کند.

یک قالب می‌تواند تمام امکانات زیرساخت را داشته باشد: کنترلر، ViewComponent، ویجت صفحه‌ساز، سرویس، کلاس تنظیمات، دسترسی، منوی پنل، Job، حتی DbContext و migration خودش، و قلاب‌ها (Event / Filter / Slot). قرارداد طراحی این است که قابلیت‌های قابل‌استفاده‌ی مجدد در افزونه ساخته شوند تا با تعویض قالب از بین نروند؛ اما اگر بخواهید، همه‌چیز می‌تواند داخل قالب باشد.

ساختار پروژه

themes/Poshesh.Theme.Default
themes/Poshesh.Theme.Default/
├── theme.json                    # شناسه، نسخه، parent، dependencies، entryAssembly
├── screenshot.svg                # تصویر پیش‌نمایش در مدیر قالب
├── DefaultTheme.cs               # ITheme + IThemeStartup — نقطه‌ی ورود
├── Themes/default/Views/         # درخت ویوها؛ {id} باید با theme.json یکی باشد
│   ├── Shared/_Layout.cshtml
│   ├── Shared/Error404.cshtml
│   ├── Widgets/{name}/Default.cshtml
│   └── Shared/Components/{Component}/Default.cshtml
├── Features/{Feature}/           # کنترلر و ویوهای خودِ قالب (پنل ادمین)
├── Settings/                     # کلاس‌های ISettings
├── Services/                     # سرویس‌های قالب
├── Widgets/                      # ویجت‌ها + IWidgetProvider
├── ViewComponents/
├── Extensibility/                # Event / Filter / Slot — خودکار کشف می‌شوند
├── Data/                         # اختیاری: DbContext و migration
├── Translations/*.json
└── wwwroot/                      # روی /_content/Theme.{id} سرو می‌شود

نقطه‌ی ورود

DefaultTheme.cs
public sealed class DefaultTheme : ITheme, IThemeStartup
{
    public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        services.AddSingleton<INavMenuLocationProvider, DefaultThemeNavLocationProvider>();
        services.AddSingleton<IWidgetProvider, DefaultThemeWidgetProvider>();
        services.AddScoped<DefaultThemeOptionsAccessor>();
        services.AddPosheshTranslations(typeof(DefaultTheme).Assembly);
    }
}

سطح ConfigureServices دقیقاً همان سطح افزونه است. قلاب‌ها نیازی به ثبت دستی ندارند: لودر خودش AddPosheshHooks را روی اسمبلی قالب صدا می‌زند.

بازنویسی ویوها — کاری که فقط قالب می‌تواند بکند

expander برای قالب فعال و سپس هر والد، این مسیرها را جلوتر از همه قرار می‌دهد:

view locations
/Themes/{id}/Views/Shared/Components/{Component}/{View}.cshtml
/Themes/{id}/Views/{Controller}/{Action}.cshtml
/Themes/{id}/Views/Shared/{View}.cshtml

هر چیزی که از موتور ویو عبور کند قابل جایگزینی است: ویوی یک feature هسته، markup یک ویجت، ViewComponent یک افزونه، layout، partial و صفحه‌ی خطا. دو استثنای عمدی: پنل ادمین پوسته‌ی ثابت خود را نگه می‌دارد، و ویویی که با مسیر صریح ~/… رندر شود از expander عبور نمی‌کند.

فصل ۲ · بخش ۹

انتشار قالب

قالب یک ماژول پروژه‌محور است، دقیقاً مثل افزونه: با اسمبلی، مهر امضا، نسخه و انتشار در مخزن. فقط یک نوع قالب وجود دارد.

  1. در theme.json شناسه‌ی canonical (lower-case)، نسخه، parent، dependencies و entryAssembly را کنترل کنید.
  2. پوشه‌ی ویوها باید Themes/{id}/Views باشد و {id} دقیقاً برابر شناسه‌ی manifest؛ مسیر ویوی کامپایل‌شده همین است و expander با همین مطابقت می‌دهد.
  3. Host نباید به پروژه‌ی قالب ProjectReference داشته باشد؛ در آن صورت قالب دوبار بارگذاری می‌شود و کنترلرهایش AmbiguousMatchException می‌دهند.
  4. دستور زیر را اجرا کنید:
publish-themes.ps1
.\eng\publish.ps1 -Target Themes

# خروجی یک قالب با شناسه canonical برابر default
Published\Themes\default\            # پوشه‌ی آماده‌ی انتشار (theme.json در ریشه)
Published\Themes\default-1.0.0.zip   # بسته‌ی قابل آپلود
Published\App\themes\default\        # همان قالب، پیش‌نصب در خروجی سرور

انتشار از پنل تحت وب

  1. در «مخزن افزونه و قالب»، برای package جدید «تعریف بسته و آپلود» و نوع قالب را انتخاب کنید.
  2. شناسه‌ی package باید دقیقاً با theme.json:id و نام پوشه‌ی نصب برابر باشد.
  3. برای نسخه‌های بعدی package را انتخاب و «نسخه جدید» را بزنید؛ version، channel، notes و ZIP قالب را وارد کنید.
  4. پس از انتشار، وضعیت Active و Listed را جداگانه کنترل کنید. سرویس manifest، parent/dependency، نسخه و ساختار archive را اعتبارسنجی و بسته را امضا می‌کند.

فصل ۲ · بخش ۱۰

چک‌لیست نهایی انتشار

قبل از تحویل یا فعال‌کردن نسخه، این کنترل کوتاه را کامل کنید. بیشتر خطاهای انتشار از اختلاف نسخه، فایل اشتباه یا انتخاب کانال نادرست می‌آیند.

پیش از ساخت

SOURCE
  • working tree و تغییرات نسخه بازبینی شده است.
  • نسخه‌ها canonical و بدون صفر اضافه‌اند.
  • build با تنظیم Release موفق است.
  • VSC production و fingerprint درست‌اند.

پیش از آپلود

PACKAGE
  • فایل از مسیر Published انتخاب شده است.
  • manifest در ریشه و نسخه/identity یکسان است.
  • کانال stable یا beta آگاهانه انتخاب شده است.
  • برای حذف فایل هسته از Build from source استفاده شده است.

پس از انتشار

VERIFY
  • پنل release را فعال و دارای فایل نشان می‌دهد.
  • نسخه‌ی جدید در channel درست دیده می‌شود.
  • نصب آزمایشی و restart با موفقیت انجام می‌شود.
  • سایت پس از نصب پاسخ و نسخه‌ی جدید را گزارش می‌کند.

خطاهای رایج

نشانهعلت محتملراه‌حل
نسخه تکراریهمان product/version قبلاً ثبت شده استنسخه را افزایش دهید؛ ترتیب upload جای نسخه را نمی‌گیرد.
بدون فایل بستهرکورد release وجود دارد اما archive در storage سرویس نیستstorage و هم‌مکانی دیتابیس/فایل را اصلاح و بسته را دوباره منتشر کنید.
ZIP رد می‌شودmanifest، identity، version یا شکل archive مطابق قرارداد نیستZIP را با publish.ps1 بسازید و مقادیر panel را با manifest یکسان کنید.
فایل قدیمی باقی می‌ماندنسخه‌ی قبلی در سرویس نبود یا archive آن خوانده نشد، پس مبنای مقایسه‌ای وجود نداشتلاگ سرویس هنگام آپلود را ببینید؛ عدد «فایل حذف‌شده» در پیام موفقیت باید با انتظار شما بخواند.
سایت نسخه را دوباره پیشنهاد می‌دهدversion.json بسته یا سایت با release برابر نیستنسخه را در منبع حقیقت اصلاح، دوباره publish و package را جایگزین کنید.

فصل ۳ · بخش ۱

چارچوب صفحه چگونه ساخته می‌شود

هر صفحهٔ عمومی از دو چیز تشکیل شده است: محتوا، و چارچوبی که دور آن کشیده می‌شود. این فصل می‌گوید چارچوب از کجا می‌آید و چه کسی می‌تواند آن را عوض کند.

سربرگ و پاصفحهٔ یک صفحه از سه سطح تصمیم می‌آید. هر سطح، سطح پایین‌تر را بازنویسی می‌کند و اگر هیچ‌کدام چیزی نگوید، طرحِ خودِ قالب نمایش داده می‌شود.

۱

قالب

مارک‌آپی که قالب داخل تگ <poshesh-header> نوشته است. پایین‌ترین سطح و همیشه موجود.

۲

تنظیمات سایت

هدر و فوتر پیش‌فرض در «قالب و لایه‌بندی». اگر انتخاب شود، جای مارک‌آپ قالب را می‌گیرد.

۳

خودِ برگه یا مطلب

هر محتوا می‌تواند هدر دیگری انتخاب کند یا بگوید اصلاً هدری نمی‌خواهم. بالاترین سطح.

تصمیمکجا گرفته می‌شوداثر
سربرگ و پاصفحهٔ پیش‌فرض/admin/settings/layoutروی همهٔ صفحاتی که چیزی نگفته‌اند
بازنویسی یک صفحهفرم برگه/مطلب یا تب «برگه» در صفحه‌سازفقط همان محتوا
صفحه اصلی سایت/admin/settings/layoutآنچه نشانی / نمایش می‌دهد
صفحهٔ مطالب/admin/settings/layoutبرگه‌ای که نشانی‌اش آرشیو مطالب را نشان می‌دهد

فصل ۳ · بخش ۲

هدر و فوتر داینامیک

هدر و فوتر در پوشش یک «سند صفحه‌ساز با نقش» است: همان ویجت‌ها، همان ویرایشگر، همان اعتبارسنجی — فقط جایی که رندر می‌شود فرق دارد.

  1. در «برگه‌ها ← هدر و فوتر» (/admin/layouts) یک مورد جدید بسازید و نوع آن را هدر یا فوتر بگذارید.
  2. پس از ذخیره، مستقیم وارد صفحه‌ساز می‌شوید و آن را مثل هر صفحهٔ دیگری می‌چینید.
  3. در «تنظیمات ← قالب و لایه‌بندی» آن را به‌عنوان هدر یا فوتر پیش‌فرض سایت انتخاب کنید.
  4. در هر برگه یا مطلب، در صورت نیاز، همان انتخاب را برای آن صفحه بازنویسی کنید.

در فرم برگه و مطلب — و در تب «برگه» داخل صفحه‌ساز — برای هرکدام از سربرگ و پاصفحه سه گزینه وجود دارد:

گزینهمعنیمقدار ذخیره‌شده
پیروی از تنظیمات سایتهرچه در «قالب و لایه‌بندی» انتخاب شده است. پیش‌فرض.Inherit
یک مورد دیگرهدر یا فوتر انتخابی، فقط برای همین محتواCustom + شناسه
بدون آنهیچ چیزی رندر نمی‌شود — نه پیش‌فرض سایت، نه مارک‌آپ قالبNone

فصل ۳ · بخش ۳

استفاده در قالب و افزونه

یک قالب با نوشتن دو تگ، هدر و فوتر داینامیک را می‌پذیرد — و اگر ننویسد، هیچ اتفاقی نمی‌افتد. قرارداد به‌گونه‌ای طراحی شده که پذیرش آن اختیاری و بی‌ریسک باشد.

محتوای داخل تگ، طرح پیش‌فرض خودِ قالب است. تا وقتی هدری انتخاب نشده باشد همان رندر می‌شود؛ به‌محض انتخاب، جای آن را می‌گیرد. پس کافی است سربرگی که از قبل داشته‌اید را داخل تگ بگذارید.

Themes/{Name}/Views/Shared/_Layout.cshtml
<poshesh-header hidden="@blankCanvas">
    <header class="my-theme-header">
        @await Component.InvokeAsync("Menu", new { location = "primary" })
    </header>
</poshesh-header>

<main>@RenderBody()</main>

<poshesh-footer hidden="@blankCanvas">
    <footer class="my-theme-footer">…</footer>
</poshesh-footer>

ویژگی hidden برای صفحات «بوم خالی» است؛ با true هیچ چارچوبی رندر نمی‌شود. قالبی که اصلاً این تگ را ننویسد، هدر داینامیک نخواهد داشت و این یک انتخاب معتبر است.

قراردادهایی که می‌توانید مصرف یا جایگزین کنید

قراردادجاکارش چیست
ISiteLayoutPartCatalogCoreفهرست هدرها و فوترها برای هر انتخابگری — بدون ارجاع به صفحه‌ساز
ISiteLayoutPolicyProviderCoreپیش‌فرض سراسری سایت؛ برای جایگزینی کل سیاست
IContentLayoutContextCoreانتخاب همین درخواست؛ هر نوع محتوایی می‌تواند آن را اعلام کند
ISiteLayoutResolverCoreنتیجهٔ نهایی پس از ادغام سه سطح؛ همان چیزی که تگ‌هلپر می‌خواند
SiteLayoutCacheTags.Part(id)Framework.Webتگ کش مشترک بین رندرکننده و سرویسی که آن را باطل می‌کند

یک نوع محتوای جدید (مثلاً «محصول» در یک افزونه) با یک خط، همین قابلیت را می‌گیرد؛ لازم نیست چیزی دربارهٔ هدرها بداند:

ProductContentService.cs
// پیش از رندر شدن Layout صدا زده می‌شود؛ MVC ابتدا View و سپس Layout را اجرا می‌کند.
contentLayout.SetChoices(
    new SiteLayoutPartChoice(product.HeaderMode, product.HeaderPartId),
    new SiteLayoutPartChoice(product.FooterMode, product.FooterPartId));

بازنویسی ظاهر رندر

خروجی هدر از یک ViewComponent قابل بازنویسی می‌آید. برای تغییر مارک‌آپ آن، این فایل را در قالب خود بسازید:

view-override.txt
themes/{Name}/Views/PageBuilder/LayoutPart/Default.cshtml

فصل ۳ · بخش ۴

صفحه اصلی و صفحهٔ مطالب

مثل وردپرس می‌توانید بگویید نشانی / چه چیزی را نشان دهد و کدام برگه، آرشیو مطالب را میزبانی کند. هر دو تنظیم در «قالب و لایه‌بندی» هستند.

حالت صفحه اصلینتیجه
صفحهٔ پیش‌فرض قالبنمای Home/Index قالب فعال. پیش‌فرض، و رفتار همهٔ سایت‌های موجود.
یک برگهٔ ثابتهمان برگه در ریشه رندر می‌شود و در نشانی خودش هم در دسترس می‌ماند.
یک فهرستفهرستی که یک ماژول عرضه کرده است؛ به‌صورت پیش‌فرض «آخرین مطالب».

صفحهٔ مطالب دقیقاً مدل وردپرس است: نشانی آن برگه آرشیو مطالب را نشان می‌دهد، عنوان و نشانی از خودِ برگه گرفته می‌شود و محتوای برگه نمایش داده نمی‌شود. مسیر /posts هم به کار خود ادامه می‌دهد.

عرضهٔ یک فهرست تازه از افزونه

هر ماژول می‌تواند فهرست خودش را به‌عنوان گزینهٔ صفحه اصلی عرضه کند. کافی است یک IFrontPageSource ثبت شود؛ نه مسیریابی تغییر می‌کند و نه صفحهٔ تنظیمات.

ShopLandingFrontPageSource.cs
internal sealed class ShopLandingFrontPageSource(ProductQueries products) : IFrontPageSource
{
    public string Key => "shop.landing";

    public string DisplayName => "صفحهٔ فرود فروشگاه";

    public async Task<ContentRenderResult?> BuildAsync(
        FrontPageRenderContext context,
        CancellationToken cancellationToken = default)
    {
        var model = await products.BuildLandingAsync(context.CanonicalPath, cancellationToken);
        return new ContentRenderResult(
            "ShopLanding",
            model,
            new ContentCacheProfile(true, ["shop:products", "site:metadata"]));
    }
}

// در Registrar افزونه:
services.AddScoped<IFrontPageSource, ShopLandingFrontPageSource>();

FrontPageRenderContext دو چیز می‌گوید: عنوانی که باید جایگزین عنوان پیش‌فرض شود (وقتی فهرست، میزبان یک برگه است) و نشانی‌ای که در آن سرو می‌شود — برای canonical و لینک‌های صفحه‌بندی.

فصل ۳ · بخش ۵

صفحه‌ساز و اعمال زندهٔ تغییرات

هدر و فوتر با همان صفحه‌ساز برگه‌ها ساخته می‌شوند، و هر تغییری که سمت سرور رندر می‌شود بلافاصله در بوم دیده می‌شود.

صفحه‌ساز سه حالت دارد: page، block و layout. حالت layout برای هدر و فوتر است و مثل بلوک رفتار می‌کند — بدون دکمهٔ انتشار، بدون تب تنظیمات برگه، و بدون امکان درج بلوک تودرتو.

مسیرکاربرد
/admin/layouts/{id}/builderویرایش دیداری هدر یا فوتر
/preview/layout/{id}?builder=trueبوم ویرایش؛ از قالب واقعی سایت رندر می‌شود
تب «برگه» در صفحه‌سازانتخاب هدر و فوتر همان برگه، بدون خروج از ویرایشگر

چه چیزی بوم را تازه می‌کند

تغییرات داخل درخت ویجت‌ها به‌صورت قطعه‌ای به بوم تزریق می‌شوند. اما هر چیزی که سرور رندر می‌کند — چارچوب صفحه، توکن‌های طراحی، بوم خالی — بیرون از آن درخت است و بارگذاری دوبارهٔ بوم لازم دارد. این موارد آن را اجرا می‌کنند:

  • ذخیرهٔ «تنظیمات سایت» (رنگ‌ها، تایپوگرافی، عرض کانتینر، CSS سراسری)
  • ذخیرهٔ «تنظیمات برگه»، از جمله تغییر هدر یا فوتر همان برگه
  • انتشار یا لغو انتشار از داخل پنل برگه
  • دکمهٔ «نوسازی بوم» در نوار بالا، برای وقتی که چیزی را بیرون از این ویرایشگر عوض کرده‌اید

فصل ۴ · بخش ۱

ورک‌فلو چیست و از کجا شروع کنیم؟

ورک‌فلو یک فرایند دیداری است: مدیر گام‌ها را روی بوم می‌چیند، مسیر میان آن‌ها را مشخص می‌کند و بدون تغییر کد، تجربه‌ای مانند ثبت‌نام را کنترل می‌کند.

هر ورک‌فلو از یک شروع، چند گام کاری و دست‌کم یک پایان تشکیل می‌شود. موتور فرایند فقط مسیری را اجرا می‌کند که شما با اتصال‌ها ساخته‌اید. برای مثال، یک ثبت‌نام ساده چنین خوانده می‌شود:

۱

شروع

بازدیدکننده وارد صفحهٔ ثبت‌نام می‌شود و اجرای تازه آغاز می‌گردد.

۲

تعامل

فرم نمایش داده می‌شود یا شمارهٔ موبایل با کد یک‌بارمصرف تأیید می‌گردد.

۳

تصمیم و عملیات

بر اساس نتیجه، حساب ساخته می‌شود، پیام فرستاده می‌شود یا کاربر به مسیر دیگری می‌رود.

۴

پایان

فرایند با نتیجه‌ای روشن مانند «حساب ساخته شد» یا «در انتظار تأیید» تمام می‌شود.

مسیرکاربرد
/admin/workflowsساخت، ویرایش، انتشار، غیرفعال‌سازی و حذف ورک‌فلوها
/admin/workflows/runsدیدن اجراهای واقعی، وضعیت آن‌ها و تاریخچهٔ هر اجرا
/admin/account/registerصفحهٔ واقعی ثبت‌نام؛ اگر حالت «فرایند طراحی‌شده» فعال باشد، ورک‌فلو در همین نشانی اجرا می‌شود
/flow/{slug}نشانی عمومی فرایندهایی که صفحهٔ اختصاصی ندارند؛ این فرایندها را هسته یا افزونه معرفی می‌کند

فصل ۴ · بخش ۲

آشنایی با محیط طراح

صفحهٔ طراح سه ستون اصلی و یک نوار فرمان دارد. اگر نقش هر قسمت را بدانید، ساخت فرایند شبیه چیدن چند کارت و وصل‌کردن آن‌هاست.

ستون ابزارها · سمت راست

همهٔ گام‌های قابل استفاده را گروه‌بندی می‌کند. نام ابزار را جست‌وجو کنید، سپس کارت آن را بکشید و روی بوم رها کنید. ابزارهای افزونه‌ها نیز همین‌جا ظاهر می‌شوند.

بوم طراحی · وسط

گره‌ها و اتصال‌ها اینجا قرار می‌گیرند. فضای خالی را بکشید تا بوم جابه‌جا شود؛ با چرخ ماوس بزرگ‌نمایی کنید و با «اندازهٔ مناسب» کل نمودار را ببینید.

تنظیمات · سمت چپ

با انتخاب یک گام، عنوان، وضعیت، فیلدها و پیام‌های اعتبارسنجی همان گام نمایش داده می‌شود. با انتخاب یک اتصال نیز مقصد آن قابل تغییر است.

نوارهای بالای صفحه

نوار اصلی
حالت روشن/تاریک، ابزارهای حرفه‌ای، آزمایش، ذخیره و انتشار. نقطهٔ کنار نام یعنی تغییر ذخیره‌نشده دارید.
وضعیت بررسی
«بدون ایراد»، تعداد هشدار یا تعداد خطا را نشان می‌دهد. روی آن کلیک کنید تا فهرست کامل باز شود؛ کلیک روی هر پیام شما را به همان گام می‌برد.
نوار بوم
بازگردانی/انجام دوباره، زوم، مرتب‌سازی خودکار، مدیریت متغیرها، رفتن سریع به یک گام و نمایش یا پنهان‌کردن دو پنل کناری.
نقشهٔ کوچک
برای نمودارهای بزرگ، نمای کلی و محدودهٔ فعلی بوم را نشان می‌دهد. روی یک گام یا بخش دیگری از نقشه کلیک کنید تا سریع جابه‌جا شوید.

برای دیدن راهنمای خودِ فرایند، روی فضای خالی بوم کلیک کنید. پنل تنظیمات، ورودی‌های آماده مانند returnUrl و نتیجه‌های قابل قبول برای گام «پایان» را نشان می‌دهد.

فصل ۴ · بخش ۳

ساخت اولین فرایند ثبت‌نام

برای شروع لازم نیست نمودار را از صفر بسازید. ورک‌فلوی «ثبت‌نام کاربر» با یک نمونهٔ کامل و قابل اجرا ایجاد می‌شود؛ آن را بررسی، آزمایش و سپس شخصی‌سازی کنید.

۱

ورود به فهرست

از منوی مدیریت، «ورک‌فلوها ← طراحی فرایندها» را باز و روی «ورک‌فلو جدید» کلیک کنید.

۲

انتخاب نوع فرایند

«ثبت‌نام کاربر» را انتخاب کنید، نامی روشن مانند «ثبت‌نام اصلی سایت» بنویسید و «ایجاد و ویرایش» را بزنید.

۳

خواندن نمونهٔ آماده

مسیر پیش‌فرض از «شروع» به «فرم ثبت‌نام» و «ساخت حساب» می‌رود. خروجی‌های ساخت حساب، مسیر موفق، در انتظار تأیید و ناموفق را جدا می‌کنند.

۴

بررسی تنظیمات

روی «فرم ثبت‌نام» کلیک کنید و فرم، عنوان دکمه و پیشوند متغیر را ببینید. روی «ساخت حساب» کلیک کنید و مطمئن شوید فیلدها از مقادیری مانند {{form.mobile}} خوانده می‌شوند.

۵

اولین شخصی‌سازی

برای نمونه، ابزار «ارسال پیامک» را میان مسیر موفق و پایان قرار دهید: خروجی «ساخته شد» را به پیامک و خروجی «ارسال شد» را به گام بعد وصل کنید.

۶

ذخیره و آزمایش

ابتدا «ذخیره»، سپس «آزمایش» را بزنید. در آزمایش هیچ حساب، پیامک یا ایمیل واقعی ساخته و ارسال نمی‌شود.

۷

انتشار و فعال‌سازی

وقتی خطای ساختاری ندارید، «انتشار» را بزنید. سپس در «تنظیمات ← ورود و ثبت‌نام» حالت «فرایند طراحی‌شده» را فعال و صفحهٔ ثبت‌نام را در یک پنجرهٔ ناشناس امتحان کنید.

فصل ۴ · بخش ۴

اتصال گام‌ها و ساخت شاخه‌ها

هر اتصال می‌گوید «پس از این نتیجه، کدام گام اجرا شود». جهت نمودار RTL است: ورودی گام در سمت راست و خروجی‌های آن در سمت چپ کارت قرار دارند.

  1. گام مبدأ را پیدا کنید و خروجی درست را بخوانید؛ برای مثال «ساخته شد»، «در انتظار تأیید» یا «ناموفق».
  2. از نقطهٔ همان خروجی بکشید. یک خط موقت همراه نشانگر ظاهر می‌شود.
  3. روی ورودی سمت راست یا هرجای بدنهٔ مقصد مکث کنید تا مقصد برجسته شود.
  4. دکمهٔ ماوس را رها کنید. مسیر منحنی با پیکان ساخته می‌شود و بررسی خودکار اجرا می‌گردد.
کارروش انجام
تغییر مقصدروی خط اتصال کلیک کنید و در پنل تنظیمات، مقصد تازه را انتخاب کنید؛ یا همان خروجی را به مقصد جدید بکشید.
حذف اتصالخط را انتخاب و Delete بزنید؛ یا راست‌کلیک و «حذف اتصال» را انتخاب کنید.
قطع همهٔ مسیرهای یک گامروی گام راست‌کلیک و «قطع اتصال‌ها» را انتخاب کنید.
ساخت دو شاخهاز هر خروجیِ گام شرط یک اتصال مستقل بسازید: «درست» به مسیر قبول و «نادرست» به مسیر جایگزین.
خروجی پویاتنظیمات گام را کامل کنید و لحظه‌ای منتظر بررسی سرور بمانید؛ خروجی‌هایی که از تنظیمات ساخته می‌شوند خودکار روی کارت تازه می‌شوند.

هر خروجی فقط یک مقصد دارد. اگر همان خروجی را دوباره وصل کنید، اتصال قبلی با مقصد جدید جایگزین می‌شود. برای فرستادن اجرا به دو مسیر متفاوت، باید از دو خروجی جدا مانند «درست/نادرست» استفاده کنید؛ یک خروجی عادی به‌صورت هم‌زمان دو مقصد ندارد.

فصل ۴ · بخش ۵

راهنمای ابزارهای ورک‌فلو

فهرست دقیق ابزارها به قابلیت‌های نصب‌شده و دسترسی مدیر بستگی دارد. ابزارهای پایه و ابزارهای فعلی پلتفرم در جدول زیر آمده‌اند.

گروه و ابزارچه کاری انجام می‌دهدنکتهٔ کاربردی
شروعنقطهٔ ورود فرایند است.هر نمودار باید یک شروع معتبر داشته باشد؛ آن را داخل Fragment قرار ندهید.
پایاناجرا را با یک نتیجهٔ مشخص تمام می‌کند.کلید یکی از «پایان‌های شناخته‌شده» همان فرایند را وارد کنید؛ مانند registered یا pending.
شرطدو مقدار را مقایسه و مسیر درست یا نادرست را انتخاب می‌کند.برای خالی‌بودن، برابری، شامل‌بودن و مقایسهٔ عددی مناسب است.
تعیین متغیریک مقدار ثابت یا ترکیبی را برای گام‌های بعد نگه می‌دارد.برای دادهٔ محرمانه گزینهٔ «مقدار حساس است» را همان ابتدا فعال کنید.
یادداشتیک توضیح در تاریخچهٔ اجرای مدیر ثبت می‌کند.برای فهمیدن تصمیم‌های مهم مفید است؛ رمز، کد یا اطلاعات حساس را در متن یادداشت ننویسید.
انتظاراجرا را تا رسیدن پاسخ بیرونی متوقف می‌کند.دلیل انتظار و نام متغیر پاسخ را روشن بنویسید؛ برای تأیید دستی یا یک رویداد بیرونی مناسب است.
تأخیراجرا را چند دقیقه، ساعت یا روز متوقف و سپس خودکار ادامه می‌دهد.برای یادآوری و پیگیری مناسب است و پس از راه‌اندازی دوبارهٔ سایت نیز ادامه پیدا می‌کند.
جست‌وجو در داده‌هایک شناسه را در منبع ثبت‌شده پیدا و نتیجه را در متغیر ذخیره می‌کند.دو خروجی «پیدا شد» و «پیدا نشد» دارد؛ نتیجه شامل مقدار، عنوان و والد است.
فرمیک فرمِ ساخته‌شده در فرم‌ساز را نشان می‌دهد و پاسخ‌ها را ذخیره می‌کند.با پیشوند form، فیلد موبایل به صورت {{form.mobile}} در دسترس است.
تأیید شماره با کدکد یک‌بارمصرف می‌فرستد و منتظر ورود کد می‌ماند.مسیرهای «تأیید شد»، «ارسال ناموفق» و «تغییر شماره» را جدا وصل کنید.
ساخت حسابحساب کاربری را با همهٔ سیاست‌های امنیتی ثبت‌نام سایت می‌سازد.سه مسیر «ساخته شد»، «در انتظار تأیید» و «ناموفق» دارد.
ورود به حسابکاربر ساخته‌شده را وارد می‌کند و سیاست عامل دوم را رعایت می‌کند.برای «نیازمند عامل دوم» و «ناموفق» نیز مقصد مشخص بسازید.
ارسال ایمیلقالب اعلان را رندر و ایمیل را برای ارسال در صف قرار می‌دهد.قالب را از فهرست انتخاب و مسیر ناموفق را مدیریت کنید.
ارسال پیامکقالب پیامک را برای گیرنده در صف ارسال می‌گذارد.در آزمایش پیام واقعی فرستاده نمی‌شود؛ نتیجهٔ ارسال واقعی در جزئیات اجرا دیده می‌شود.

فصل ۴ · بخش ۶

تنظیمات، عبارت‌ها و متغیرها

متغیر ظرفی نام‌دار برای داده است. یک گام مقدار را می‌سازد و گام بعد با نوشتن {{نام}} آن را می‌خواند؛ پنل تنظیمات برای بیشتر فیلدها انتخاب‌گر متغیر دارد.

ورودی فرایند

پیش از شروع آماده است؛ در ثبت‌نام، returnUrl مسیر بازگشت پس از موفقیت را نگه می‌دارد.

خروجی گام‌ها

ابزارها مقدارهایی مانند شمارهٔ تأییدشده، شناسهٔ کاربر یا نتیجهٔ جست‌وجو را تولید می‌کنند.

متغیر اعلام‌شده

مدیر آن را از دکمهٔ { } بالای بوم می‌سازد و نوع، مقدار اولیه و حساس‌بودن را تعیین می‌کند.

چند نمونهٔ خواندن مقدار

Workflow expressions
{{form.mobile}}
{{form.firstName}} عزیز، خوش آمدید
{{lookup.label}}
/my?return={{returnUrl}}

اگر کل فیلد فقط یک توکن باشد، مقدار اصلی آن ــ حتی عدد، بله/خیر یا شیء JSON ــ حفظ می‌شود. اگر توکن داخل یک جمله باشد، مقدار به متن تبدیل و در همان جای جمله قرار می‌گیرد. برای جلوگیری از غلط تایپی، از فهرست «درج متغیر…» کنار فیلد استفاده کنید.

مدیریت متغیرهای فرایند

  1. در نوار بوم روی دکمهٔ { } کلیک کنید؛ عدد کنار آن تعداد متغیرهای اعلام‌شده را نشان می‌دهد.
  2. «افزودن متغیر» را بزنید و یک نام فنی مانند profile.segment و یک عنوان قابل فهم بنویسید.
  3. نوع را از متن، عدد، بله/خیر، تاریخ‌وزمان یا دادهٔ JSON انتخاب کنید و در صورت نیاز مقدار اولیه بدهید.
  4. تعداد استفاده‌ها کنار هر متغیر دیده می‌شود. تغییر نام، ارجاع‌های شناخته‌شده را نیز بازنویسی می‌کند؛ حذف، ارجاع‌های باقی‌مانده را برای اصلاح مشخص نگه می‌دارد.
نوع فیلد در تنظیماتنحوهٔ استفاده
عبارت و مسیرمتن ثابت یا متغیر درج کنید؛ پیش‌نمایش عبارت کمک می‌کند نتیجه را قبل از اجرا ببینید.
انتخاب‌گرفرم، منبع داده، قالب ایمیل/پیامک، نقش، مجوز یا مسیر را از فهرست انتخاب کنید.
مدتمقدار را با واحد دقیقه، ساعت یا روز وارد کنید؛ طراح آن را به مقدار استاندارد تبدیل می‌کند.
نام متغیرنام مقصدی است که ابزار نتیجه را در آن می‌نویسد؛ پیشنهادهای موجود از غلط تایپی جلوگیری می‌کنند.

فصل ۴ · بخش ۷

بررسی، آزمایش، ذخیره و انتشار

چرخهٔ امن کار این است: نمودار را کامل کنید، پیام‌های بررسی را بخوانید، پیش‌نویس را ذخیره کنید، اجرای آزمایشی بگیرید و در پایان انتشار دهید.

عملاثرچه زمانی انجام شود
بررسی خودکارپس از هر تغییر، خطاها، هشدارها و خروجی‌های پویا را از سرور تازه می‌کند.همیشه فعال است؛ روی نشان وضعیت کلیک کنید.
ذخیرههمین پیش‌نویس را نگه می‌دارد؛ حتی نمودار نیمه‌کاره و دارای هشدار قابل ذخیره است.مرتب و پیش از خروج؛ میانبر Ctrl+S.
آزمایشفرایند را با ورودی JSON اجرا، اثرهای بیرونی را شبیه‌سازی و Timeline تولید می‌کند.پس از هر تغییر مهم و پیش از انتشار.
انتشارنسخه را ثابت و فعال می‌کند و یک پیش‌نویس با شمارهٔ بعدی می‌سازد.پس از رفع خطاها، بررسی هشدارها و تأیید نتیجهٔ آزمایش.

خطا با هشدار چه تفاوتی دارد؟

خطا یعنی نمودار از نظر ساختاری قابل اجرا نیست؛ مانند نبودن شروع، ابزار ناشناخته یا اتصال به گام حذف‌شده. انتشار تا رفع آن ممکن نیست. هشدار دربارهٔ ریسک یا مسیر ناقص است؛ مانند گام دور از دسترس یا خروجی باز. هشدار جلوی انتشار را نمی‌گیرد، اما باید آگاهانه پذیرفته شود.

اجرای آزمایشی را چگونه بخوانیم؟

  1. روی «آزمایش» کلیک کنید. ورودی پیشنهادی بر اساس متغیرهای فرایند ساخته می‌شود؛ آن را به شکل یک شیء JSON ویرایش کنید.
  2. «شروع آزمایش» را بزنید. متن ورودی نباید بیشتر از ۶۴ کیلوبایت باشد و باید با { } شروع و پایان یابد.
  3. خلاصه، وضعیت، تعداد گام‌ها، زمان کل و کندترین گام را بررسی کنید.
  4. در Timeline روی هر ردیف کلیک کنید یا با قبلی/بعدی حرکت کنید؛ همان گام روی بوم پیدا و برجسته می‌شود.
  5. متغیرهای خروجی را باز کنید. مقدارهای حساس پوشانده شده‌اند و نباید برای رفع اشکال آشکار شوند.
Test input example
{
  "returnUrl": "/my"
}

فصل ۴ · بخش ۸

ابزارهای حرفه‌ای طراحی

برای نمودارهای بزرگ، طراح امکانات چیدمان، بازاستفاده، انتقال و کنترل نسخه دارد. این ابزارها سرعت کار را بالا می‌برند، ولی هیچ‌کدام بدون ذخیره یا انتشار، نسخهٔ فعال را تغییر نمی‌دهند.

انتخاب و چیدمان گروهی

انتخاب چندگانه

Shift را نگه دارید و روی فضای خالی یک کادر بکشید؛ یا با Ctrl روی گام‌ها کلیک کنید. نوار شناور تعداد گام‌های انتخاب‌شده را نشان می‌دهد.

هم‌ترازی و توزیع

گام‌ها را از چپ، مرکز، راست، بالا یا پایین هم‌تراز کنید. برای سه گام یا بیشتر، فاصلهٔ افقی یا عمودی را یکنواخت کنید.

بازگردانی و کپی

تا ۵۰ تغییر اخیر قابل بازگردانی است. کپی/چسباندن و تکرار گروهی، اتصال‌های داخلیِ انتخاب را نیز حفظ می‌کنند.

امکانکاربرد و محدودیت
مرتب‌سازی خودکارنمودار درهم را از راست به چپ و بر اساس فاصله از شروع مرتب می‌کند. موقعیت‌ها بعداً همچنان قابل ویرایش‌اند.
رفتن به گامنام گام را از فهرست بالای بوم انتخاب کنید تا بدون جست‌وجوی دستی در مرکز دید قرار گیرد.
حالت تمرکزهر دو پنل کناری را پنهان می‌کند. نمایش هر پنل جداگانه نیز ممکن است و انتخاب شما در همان مرورگر حفظ می‌شود.
خروجی JSONگام‌ها، اتصال‌ها، متغیرها و تنظیمات نسخهٔ فعلی را در فایل .workflow.json نگه می‌دارد. فایل ممکن است مقدارهای اولیه را داشته باشد؛ آن را مانند دادهٔ مدیریتی محافظت کنید.
ورود JSONفایل حداکثر یک مگابایت را پس از بررسی نوع فرایند، اندازه، ابزارهای نصب‌شده و سلامت اتصال‌ها جایگزین پیش‌نویس می‌کند. با بازگردانی قابل برگشت است.
Fragmentحداکثر ۵۰ گام انتخاب‌شده و اتصال‌های داخلی را به‌عنوان قطعهٔ قابل بازاستفاده ذخیره می‌کند؛ گام شروع داخل آن قرار نمی‌گیرد.
مقایسهٔ نسخه‌هاپیش‌نویس را با یکی از ۵۰ نسخهٔ اخیر مقایسه و گام افزوده، حذف‌شده، تغییرکرده، اتصال و متغیر تغییرکرده را گزارش می‌کند.
بارگذاری نسخهٔ قدیمینمودار انتخاب‌شده را فقط روی پیش‌نویس می‌آورد؛ نسخهٔ منتشرشده تغییر نمی‌کند تا شما ذخیره و انتشار تازه انجام دهید.

ساخت و استفاده از Fragment

  1. گام‌های یک الگوی تکراری ــ مانند «تأیید موبایل و مسیر خطا» ــ را انتخاب کنید.
  2. از نوار بالا «ابزارهای حرفه‌ای» را باز، نامی روشن وارد و «ذخیرهٔ انتخاب» را بزنید.
  3. در نمودار سازگار بعدی، همان پنجره را باز و «درج روی بوم» را انتخاب کنید. متغیرهای لازم که هنوز وجود ندارند نیز افزوده می‌شوند.
میانبرکار
Ctrl+Sذخیرهٔ پیش‌نویس
Ctrl+Z / Ctrl+Yبازگردانی / انجام دوباره
Ctrl+C / Ctrl+Vکپی / چسباندن گام‌های انتخاب‌شده با اتصال‌های داخلی
Ctrl+Dتکرار انتخاب
Ctrl+Aانتخاب همهٔ گام‌ها
Deleteحذف گام‌ها یا اتصال انتخاب‌شده
/رفتن به جست‌وجوی ابزارها
Fجا دادن کل نمودار در بوم
کلیدهای جهتجابه‌جایی دقیق انتخاب؛ همراه Shift با گام بزرگ‌تر

فصل ۴ · بخش ۹

اجراها، دسترسی‌ها و رفع اشکال

بعد از انتشار، بخش «اجراها» پاسخ می‌دهد چه کسی در کدام گام مانده، فرایند چگونه تمام شده و عملیات‌هایی مانند پیامک با چه وضعیتی تحویل شده‌اند.

خواندن صفحهٔ اجراها

در حال اجرا
موتور هنوز مشغول پردازش گام‌های قابل اجراست.
در انتظار
فرایند منتظر فرم، کد، زمان، تأیید یا پاسخ بیرونی است. نوع انتظار و گام فعلی در جزئیات نمایش داده می‌شود.
تمام‌شده
فرایند به پایان رسیده و نتیجهٔ آن مانند registered ثبت شده است.
خطا یا لغوشده
کد و پیام خطا، آخرین گام و Timeline را بررسی کنید. مدیر دارای مجوز می‌تواند اجرای زنده یا منتظر را لغو کند.

جزئیات هر اجرا، نسخهٔ ورک‌فلو، زمان شروع و پایان، گام فعلی، نتیجه و تاریخچهٔ گام‌ها را با مدت هر مرحله نشان می‌دهد. برای حفاظت از اطلاعات شخصی، متغیرهای کامل اجرا در این صفحه نمایش داده نمی‌شوند. اگر گام دارای اثر بیرونی باشد، بخش «عملیات‌های پس‌زمینه» وضعیت در انتظار، در حال ارسال، ارسال‌شده یا ناموفق، تعداد تلاش و آخرین خطا را جدا نشان می‌دهد.

سطوح دسترسی پیشنهادی

مجوزاختیاربرای چه نقشی
admin.workflows.viewدیدن فهرست ورک‌فلو و تاریخچهٔ اجراهای پایان‌یافتهپشتیبانی و ناظر فرایند
admin.workflows.manageساخت، طراحی، ذخیره، حذف و اجرای آزمایشیطراح فرایند
admin.workflows.publishفعال‌کردن نسخه برای کاربران یا غیرفعال‌سازی آنمدیر انتشار
admin.workflows.runsدیدن اجرای زنده و لغو اجرای در حال اجرا یا منتظراپراتور مورد اعتماد

خطاهای رایج و راه‌حل سریع

نشانهعلت محتملراه‌حل
دو گام وصل نمی‌شوندکشیدن از بدنهٔ کارت یا رهاکردن پیش از برجسته‌شدن مقصداز نقطهٔ خروجی رنگیِ سمت چپ مبدأ بکشید و روی ورودی یا بدنهٔ مقصدِ برجسته رها کنید.
اتصال قبلی ناپدید شدهمان خروجی به مقصد تازه وصل شده استهر خروجی فقط یک مقصد دارد؛ برای دو مسیر از گام شرط یا خروجی‌های جدا استفاده کنید.
خروجی‌های مورد انتظار دیده نمی‌شوندتنظیم گام کامل نشده یا خروجی پویا هنوز اعتبارسنجی نشده استتنظیم را کامل کنید، بیرون فیلد کلیک کنید، لحظه‌ای صبر و فهرست بررسی‌ها را باز کنید.
ابزار قرمز یا ناشناخته استافزونهٔ صاحب ابزار غیرفعال یا حذف شده استافزونه را برگردانید یا گام را با ابزار نصب‌شده جایگزین کنید.
ذخیره با تداخل رد می‌شودپیش‌نویس در تب یا نشست دیگری زودتر ذخیره شده استدر صورت نیاز JSON بگیرید، صفحه را تازه کنید و تغییر را روی آخرین نسخه اعمال کنید.
آزمایش روی «در انتظار» می‌ماندبه فرم، کد تأیید، انتظار یا رویداد زمان‌دار رسیده استTimeline و «در انتظار چه چیزی» را بخوانید؛ این وضعیت برای گام‌های تعاملی طبیعی است.
پیامک یا ایمیل آزمایشی نرسیداثرهای بیرونی در آزمایش عمداً شبیه‌سازی می‌شوندبرای آزمون واقعی، نسخه را با گیرندهٔ کنترل‌شده منتشر و وضعیت عملیات پس‌زمینه را بررسی کنید.
تغییر برای بازدیدکننده دیده نمی‌شودفقط ذخیره شده، منتشر نشده یا حالت ثبت‌نام هنوز استاندارد استانتشار را انجام دهید و برای ثبت‌نام، «فرایند طراحی‌شده» را در تنظیمات ورود و ثبت‌نام فعال کنید.
مقدار در گزارش پوشانده شده استمتغیر حساس استاین رفتار امنیتی صحیح است؛ برای رفع اشکال از مسیر اجرا و پیام‌های غیرحساس استفاده کنید.
  • هر خروجی مهم به مقصد روشن متصل است و هر مسیر به «پایان» می‌رسد.
  • هیچ خطای ساختاری باقی نمانده و هشدارها آگاهانه بررسی شده‌اند.
  • متغیرهای محرمانه حساس‌اند و یادداشت‌ها حاوی رمز یا کد نیستند.
  • آزمایش Timeline قابل انتظار دارد و گام کند یا مسیر اشتباه دیده نمی‌شود.
  • پس از انتشار، صفحهٔ واقعی در حالت ناشناس و با یک دادهٔ کنترل‌شده آزمایش شده است.
  • در اجرای واقعی، نتیجه و وضعیت عملیات‌های پس‌زمینه از بخش «اجراها» کنترل شده است.

فصل ۰ · بخش ۱

افزودن فصل، بخش، کد و تصویر

هر فصل یک گروه بازشونده در منو دارد و هر موضوع داخل آن یک <section> مستقل است. با این الگو می‌توان فصل و بخش تازه را بدون تغییر در استایل صفحه اضافه کرد.

  1. برای فصل جدید، یک nav-chapter با عنوان و شماره‌ی فصل در محدوده‌ی DOC-NAV بسازید.
  2. برای هر بخش، یک section.doc-section با id انگلیسی و یکتا بسازید.
  3. لینک بخش را با شماره‌ای مانند ۳.۱ داخل زیرمنوی همان فصل قرار دهید.
  4. عنوان را کوتاه و متن را با جمله‌های صریح نگه دارید؛ هر پاراگراف فقط یک نکته.
  5. برای کد از code-shell استفاده کنید تا متن همیشه LTR و مناسب کپی باشد.
  6. برای تصویر از figure.media-frame استفاده و زیرنویس کوتاه اضافه کنید.
chapter-template.html
<div class="nav-chapter" data-chapter>
    <button class="nav-chapter__toggle" type="button"
            aria-expanded="false" aria-controls="chapter-3-menu">
        <span class="nav-chapter__heading">
            <span class="nav-chapter__number">فصل ۳</span>
            <span class="nav-chapter__title">افزونه‌ها</span>
        </span>
        <svg class="nav-chapter__chevron" viewBox="0 0 24 24"
             fill="none" stroke="currentColor" stroke-width="1.8">
            <path d="m6 9 6 6 6-6"/>
        </svg>
    </button>

    <div class="nav-chapter__sections" id="chapter-3-menu">
        <div class="nav-chapter__sections-inner">
            <a href="#plugin-intro" data-nav-link>
                <span class="nav-section__number">۳.۱</span>
                <span>افزونه چیست؟</span>
            </a>
        </div>
    </div>
</div>
section-template.html
<section class="doc-section" id="topic-id" data-doc-section>
    <div class="section-head">
        <div>
            <p class="section-kicker">فصل ۳ · بخش ۱</p>
            <h2>عنوان کوتاه و روشن</h2>
            <p>در یک جمله بگویید این بخش چه مسئله‌ای را حل می‌کند.</p>
        </div>
    </div>

    <p>متن اصلی بخش…</p>
</section>

<!-- لینک متناظر در زیرمنوی فصل -->
<a href="#topic-id" data-nav-link>
    <span class="nav-section__number">۳.۱</span>
    <span>عنوان کوتاه و روشن</span>
</a>
محل نمونه برای تصویر فرایند یا اسکرین‌شات این بلوک را با img جایگزین کنید؛ تصویر را کنار فایل یا در learn/images نگه دارید.
شکل ۱ — زیرنویس باید کوتاه توضیح دهد تصویر چه چیزی را ثابت یا روشن می‌کند.
image-template.html
<figure class="media-frame">
    <img src="images/request-flow.webp"
         alt="مسیر درخواست از Host تا PlatformDbContext"
         loading="lazy">
    <figcaption>شکل ۲ — مسیر پردازش یک درخواست HTTP.</figcaption>
</figure>