Poshesh.Framework.Core
BASEقراردادها، primitiveها، مدلهای مشترک، Result، eventها، permissionها و extension pointهای عمومی.
مستند زندهی فنی پروژه
مرجع سریع و خوانای معماری، زیرساخت و فرایندهای فنی Poshesh. هر فصل یک موضوع مستقل را از تصمیمهای پایه تا اجرای عملی و چکلیست نهایی، کوتاه و مرحلهبهمرحله توضیح میدهد.
از اینجا شروع کنید
هر فصل مستقل است. برای یادگیری، بخشهای هر فصل را بهترتیب بخوانید؛ برای مراجعهی روزمره، مستقیم به موضوع موردنظر بروید.
روش استاندارد افزودن فصل، بخش، کد و تصویر
پوشهها، پروژهها، وابستگیها و مرزهای معماری
ساخت خروجی، استقرار سایت و انتشار هسته، افزونه و قالب
چارچوب صفحه، هدر و فوتر داینامیک، صفحه اصلی و اتصال آنها به قالب و افزونه
آموزش سادهٔ ساخت فرایند، اتصال گامها، متغیرها، آزمایش، انتشار و پایش اجراها
فصل ۱ · بخش ۱
Poshesh یک CMS و سایتساز «پلتفرممحور» است؛ هستهی نصب بهتنهایی یک موتور کامل سایت است و امکانات اختیاری بهشکل افزونه وارد میشوند.
قراردادهای عمومی در پایینترین لایه قرار دارند. پیادهسازیها و UI روی آنها ساخته میشوند. نتیجه این است که هسته قابلاستفاده میماند و جزئیات وب، EF Core یا یک قابلیت خاص به قراردادهای پایه نشت نمیکند.
فصل ۱ · بخش ۲
این نقشه محل هر خانوادهی کد را نشان میدهد. پوشههای تولیدشده مانند bin و obj عمداً نمایش داده نشدهاند.
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 | تنها محل فایلهای قابلتحویل به سرور یا مشتری است. |
فصل ۱ · بخش ۳
نام پروژه بهتنهایی کافی نیست. این فهرست میگوید هر پروژه چه کاری انجام میدهد و چه چیزی نباید وارد آن شود.
قراردادها، primitiveها، مدلهای مشترک، Result، eventها، permissionها و extension pointهای عمومی.
پیادهسازی زیرساخت مشترک: convention و interceptorهای EF، cache، job، storage، audit، secret و update client.
چسب MVC و HTTP: pipeline، امنیت، theme engine، plugin loader، view location، assetها، panelها و widget pipeline.
تمام قابلیتهای داخلی CMS در Features/*، بههمراه PlatformDbContext، migrationها، viewها و assetهای پنل.
Composition root و برنامهی قابل اجرا. تنظیمات، Program.cs، نسخهی سایت و فایلهای میزبان اینجاست. Host به هیچ افزونه یا قالبی ارجاع ندارد؛ هر دو در زمان اجرا کشف و بارگذاری میشوند.
ارکستریشن توسعه با .NET Aspire؛ اجرای راحت Host و منابعی مانند SQL Server.
پیشفرضهای مشترک OpenTelemetry، health check و resilience برای سرویسهای اجرایی.
قالب عمومی پیشفرض بهشکل یک ماژول کامل: manifest، اسمبلی ورودی، ویوها، ویجت، تنظیمات و کنترلر خودش، ترجمهها و wwwroot.
تستهای واحد و NetArchTest برای قفلکردن مرزهای معماری، بهویژه استقلال featureها.
ابزار مستقل و کموابستگی برای اعمال آفلاین بستهی بهروزرسانی و راهاندازی دوبارهی سایت.
| پروژه | نقش | وابستگی مستقیم |
|---|---|---|
| Poshesh.Plugin.HelloWorld | نمونهی کوچک مجوز، منوی پنل، تنظیمات و hook | Framework.Web |
| Poshesh.Plugin.Projects | نمونهی افزونهی دادهدار با DbContext و migration مستقل، widget و API | Framework.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 برای Shop | Framework.Web + Shop.Contracts |
سرویس جداگانهی انتشار نسخه، ثبت سایت، مجوز، heartbeat، بستههای بهروزرسانی و امضای آنها.
پنل تحت وب اپراتور برای مدیریت Versioning API: انتشار بستهها، سایتها، لایسنس، مخزن افزونه و تنظیمات سرویس.
پنل ویندوزی پیشین همان سرویس. جای خود را به پنل تحت وب داده و برای کارهای روزمره استفاده نمیشود.
فصل ۱ · بخش ۴
فلش یعنی «پروژهی سمت راست به پروژهی سمت چپ ارجاع دارد». مسیر اصلی یکطرفه و قابل پیشبینی است.
کد داخلی Platform با assembly scanning پیدا نمیشود. Host بهصورت صریح Framework، Platform و Theme را ثبت میکند؛ خود Platform نیز فهرست ثابت و مرتبشدهی registrarها را اجرا میکند.
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 نشان میدهد.
Poshesh.Web محیط، appsettings، نسخه و سرویسهای مشترک را آماده میکند.
AddPoshesh() زیرساخت، MVC، امنیت، localization، theme engine، plugin runtime و قراردادهای عمومی را متصل میکند.
AddPlatform() در صورت وجود connection string، DbContext را ثبت و registrarهای ثابت featureها را بهترتیب اجرا میکند.
Permission، menu، theme، widget، post type و سایر providerها در startup جمع و سپس immutable میشوند.
UsePoshesh() middlewareهای امنیت، culture، routing، audit context، static assets و endpointها را با ترتیب ثابت میچیند.
Controller یا content route handler درخواست را میگیرد؛ permission و antiforgery در مرز وب بررسی میشوند.
Command service از Result استفاده میکند؛ query service با AsNoTracking() مدل خواندن را میسازد. DbContext همان Unit of Work است.
پنل ادمین از پوستهی ثابت Velzon استفاده میکند. سایت عمومی از زنجیرهی active theme → parent → feature → platform view میگیرد.
فصل ۱ · بخش ۶
Platform یک پروژه است، اما ساختار داخلی آن feature-first است. هر قابلیت، فایلهای دامنه تا UI خودش را کنار هم نگه میدارد.
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 کمتر یا بیشتر باشند؛ اصل مهم این است که فایلهای یک قابلیت کنار هم بمانند و برای همکاری با قابلیت دیگر از قرارداد مشترک عبور کنند.
فصل ۱ · بخش ۷
این قواعد سلیقهای نیستند؛ بخشی از آنها با NetArchTest کنترل میشوند و بخش دیگر قرارداد پایدار توسعهی پروژهاند.
Platform/Composition صریح و مرتب است.// نادرست: وابستگی مستقیم به slice دیگر
using Poshesh.Platform.Features.Taxonomy.Domain;
// درست: قرارداد feature-neutral در Framework.Core
public sealed class PostService(IContentTaxonomyService taxonomy)
{
// همکاری از مرز عمومی و پایدار انجام میشود.
}
فصل ۱ · بخش ۸
پیش از ساخت پوشه یا پروژهی تازه، نوع تغییر را مشخص کنید. این جدول مسیر معمول را نشان میدهد.
Framework.Core؛ فقط وقتی چند مصرفکننده به یک مرز پایدار نیاز دارند.Framework.Infrastructure؛ مانند cache، storage، background job یا convention دیتابیس.Framework.Web؛ مانند middleware، TagHelper، theme/plugin glue یا asset resolver.Platform/Features/{Name} و ثبت صریح registrar آن در composition.plugins/؛ اگر داده دارد با DbContext و migration مستقل.themes/: یک پروژهی قالب بسازید یا ویوی موردنظر را در قالب فعال override کنید (docs/themes.md).Poshesh.Web؛ فقط composition و configuration، نه business logic.tools/ یا زیرسامانهای با مرز استقرار روشن؛ ساخت پروژهی تازه باید تصمیم معماری باشد.فصل ۲ · بخش ۱
در Poshesh «ساخت خروجی»، «دیپلوی اولیه» و «انتشار نسخه» سه کار مرتبط اما متفاوتاند. نقطهی مشترک همهی آنها پوشهی Published است.
نسخهی هسته در version.json و نسخهی افزونه یا قالب در manifest همان بسته قرار دارد.
eng/publish.ps1 سایت، Updater، افزونهها و قالبها را پاکسازی و بستهبندی میکند و قالبها را در خروجی سرور پیشنصب میگذارد.
Published/App برای سرور؛ ZIP هسته برای Versioning؛ ZIP افزونه و قالب برای مخزن افزونههاست.
سرور تازه فایلهای App را میگیرد. نسخههای قابل بهروزرسانی با آپلود ZIP در پنل تحت وب منتشر و امضا میشوند.
شماره نسخه، کانال، وضعیت فعال، وجود فایل بسته و پاسخ سایت پس از نصب را کنترل کنید.
| کار | ورودی صحیح | مقصد |
|---|---|---|
| Initial deployment | Published/App | ریشهی برنامه روی سرور مشتری |
| Core update | Published/poshesh-{version}.zip آپلودشده در پنل | Versioning service → سایتهای متصل |
| Plugin release | Published/Plugins/{id}-{version}.zip | مخزن افزونه و قالب در Versioning |
| Theme release | Published/Themes/{id}-{version}.zip | مخزن افزونه و قالب در Versioning |
فصل ۲ · بخش ۲
اسکریپت را از ریشهی مخزن و با PowerShell 7 اجرا کنید. اجرای بدون پارامتر همهی خروجیها را با تنظیم Release میسازد.
cd D:\Github.com\YektaBrick
pwsh -File .\eng\publish.ps1
اگر ExecutionPolicy جلوی اجرای اسکریپت را گرفت، فقط برای همین پردازش از دستور زیر استفاده کنید:
pwsh -ExecutionPolicy Bypass -File .\eng\publish.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 فقط برای آزمایش محلیاند و نباید تحویل شوند.
| پارامتر | پیشفرض | کاربرد |
|---|---|---|
| -Target | All | All، App، Plugins یا Themes. فقط خانوادهی انتخابشده ساخته میشود. |
| -Version | نسخهی فعلی | فقط در ساخت App مصرف میشود؛ version.json را پیش از publish بازنویسی و نام ZIP هسته را تعیین میکند. |
| -ProductCode | poshesh | نام محصول در manifest و نام ZIP هسته. معمولاً تغییر ندهید. |
| -Channel | stable | کانال manifest هسته: stable یا beta. کانال افزونه/قالب هنگام انتشار در پنل انتخاب میشود. |
| -NoZip | خاموش | ZIP هسته، افزونه و قالب را نمیسازد و فقط پوشههای آماده را باقی میگذارد. |
| -Configuration | Release | تنظیم build. مقدار دیگر بهطور پیشفرض رد میشود. |
| -AllowNonRelease | خاموش | فقط برای آزمایش محلی؛ هرگز خروجی آن را به مشتری یا Versioning ندهید. |
فصل ۲ · بخش ۴
پس از پایان اسکریپت، summary پایانی مسیر دقیق خروجیهای همین اجرا را نشان میدهد. فایل مناسب را از این ساختار بردارید.
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 است. محتویات آن بدون ساخت دوباره روی سرور قرار میگیرد.manifest.json فقط داخل آرشیو است و داخل App قرار نمیگیرد.appsettings.Local.json، appsettings.Development.json و PDB نباید در خروجی مشتری باشند.فصل ۲ · بخش ۵
برای نصب تازه، ZIP بهروزرسانی را extract نکنید. خروجی صحیح، پوشهی کامل Published/App است که Updater را نیز همراه دارد.
GET /api/public/info باید fingerprint مورد انتظار production را برگرداند.publish.ps1 -Version x.y.z -Target App را اجرا کنید.Published/App را به app root سرور منتقل کنید. وجود updater/Poshesh.Updater.exe را جداگانه بررسی کنید.appsettings.Local.json مخصوص همان سرور را میسازد.5ABA6781481EABF9DF92E148921BCB78A75D1A901DB4DAA80200861DC7B00D8B
فصل ۲ · بخش ۶
یک مسیر بیشتر نیست: با publish.ps1 بسته را بسازید و در پنل تحت وب آپلود کنید. سرویس هنگام آپلود manifest را بازنویسی میکند و فهرست فایلهای حذفشده را خودش میسازد.
.\eng\publish.ps1 -Version 1.2.0 -Target App
git diff -- src\Host\Poshesh.Web\version.json
| مرحله | مجری | نتیجه |
|---|---|---|
نوشتن version.json و ساخت خروجی Release | eng/publish.ps1 | Published/App و Published/poshesh-{version}.zip |
| inventory اولیه با SHA-256 | eng/publish.ps1 | manifest.json داخل ZIP با deleted خالی |
مقایسه با نسخهی قبلی و ساخت deleted | سرویس، هنگام آپلود | manifest بازنویسی و جایگزین میشود |
| hash و امضای ECDSA | سرویس، پس از بازنویسی | امضا روی فایل نهایی، نه فایل آپلودشده |
publish.ps1 -Version بسازید و تغییر version.json را commit کنید.poshesh، نسخه را دقیقاً برابر version.json و کانال را stable یا beta بگذارید.Published/poshesh-{version}.zip را انتخاب و توضیحات نسخه را کوتاه و کاربردی بنویسید.پس از فعالشدن release، مدیر سایت میتواند از /admin/system/update بهروزرسانی را شروع کند. اپراتور مرکزی نیز در صفحهی «سایتهای نصبشده» یک سایت را انتخاب و «بروزرسانی از راه دور» را میزند؛ چند لحظه بعد «بررسی زنده» وضعیت بازگشت سایت را تأیید میکند.
فصل ۲ · بخش ۷
نسخه و هویت افزونه از plugin.json میآید. اسکریپت همهی پوشههای دارای این manifest را publish و برای مخزن بستهبندی میکند.
plugin.json مقدارهای id و version را بررسی کنید. شناسه باید lower-case و با نام package و پوشهی نصب دقیقاً یکسان باشد.entryAssembly یا DLL پیشفرض افزونه در خروجی وجود خواهد داشت و dependencyها درستاند..\eng\publish.ps1 -Target Plugins
# خروجی نمونه
Published\Plugins\projects\
Published\Plugins\projects-1.0.0.zip
plugin.json:version برابر باشد. کانال، توضیحات و ZIP ساختهشده را انتخاب و «آپلود و انتشار» را اجرا کنید.فصل ۲ · بخش ۸
قالب و افزونه یک چیزند: پروژه، manifest، اسمبلی ورودی، load context مستقل. تفاوت فقط در نقش است — افزونه «کار سایت» را میسازد و قالب «ظاهر سایت» را، و قالب تنها ماژولی است که میتواند هر ویویی را در برنامه جایگزین کند.
یک قالب میتواند تمام امکانات زیرساخت را داشته باشد: کنترلر، ViewComponent، ویجت صفحهساز، سرویس، کلاس تنظیمات، دسترسی، منوی پنل، Job، حتی DbContext و migration خودش، و قلابها (Event / Filter / Slot). قرارداد طراحی این است که قابلیتهای قابلاستفادهی مجدد در افزونه ساخته شوند تا با تعویض قالب از بین نروند؛ اما اگر بخواهید، همهچیز میتواند داخل قالب باشد.
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} سرو میشود
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 برای قالب فعال و سپس هر والد، این مسیرها را جلوتر از همه قرار میدهد:
/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 عبور نمیکند.
فصل ۲ · بخش ۹
قالب یک ماژول پروژهمحور است، دقیقاً مثل افزونه: با اسمبلی، مهر امضا، نسخه و انتشار در مخزن. فقط یک نوع قالب وجود دارد.
theme.json شناسهی canonical (lower-case)، نسخه، parent، dependencies و entryAssembly را کنترل کنید.Themes/{id}/Views باشد و {id} دقیقاً برابر شناسهی manifest؛ مسیر ویوی کامپایلشده همین است و expander با همین مطابقت میدهد.ProjectReference داشته باشد؛ در آن صورت قالب دوبار بارگذاری میشود و کنترلرهایش AmbiguousMatchException میدهند..\eng\publish.ps1 -Target Themes
# خروجی یک قالب با شناسه canonical برابر default
Published\Themes\default\ # پوشهی آمادهی انتشار (theme.json در ریشه)
Published\Themes\default-1.0.0.zip # بستهی قابل آپلود
Published\App\themes\default\ # همان قالب، پیشنصب در خروجی سرور
theme.json:id و نام پوشهی نصب برابر باشد.فصل ۲ · بخش ۱۰
قبل از تحویل یا فعالکردن نسخه، این کنترل کوتاه را کامل کنید. بیشتر خطاهای انتشار از اختلاف نسخه، فایل اشتباه یا انتخاب کانال نادرست میآیند.
| نشانه | علت محتمل | راهحل |
|---|---|---|
| نسخه تکراری | همان 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 | برگهای که نشانیاش آرشیو مطالب را نشان میدهد |
فصل ۳ · بخش ۲
هدر و فوتر در پوشش یک «سند صفحهساز با نقش» است: همان ویجتها، همان ویرایشگر، همان اعتبارسنجی — فقط جایی که رندر میشود فرق دارد.
/admin/layouts) یک مورد جدید بسازید و نوع آن را هدر یا فوتر بگذارید.در فرم برگه و مطلب — و در تب «برگه» داخل صفحهساز — برای هرکدام از سربرگ و پاصفحه سه گزینه وجود دارد:
| گزینه | معنی | مقدار ذخیرهشده |
|---|---|---|
| پیروی از تنظیمات سایت | هرچه در «قالب و لایهبندی» انتخاب شده است. پیشفرض. | Inherit |
| یک مورد دیگر | هدر یا فوتر انتخابی، فقط برای همین محتوا | Custom + شناسه |
| بدون آن | هیچ چیزی رندر نمیشود — نه پیشفرض سایت، نه مارکآپ قالب | None |
فصل ۳ · بخش ۳
یک قالب با نوشتن دو تگ، هدر و فوتر داینامیک را میپذیرد — و اگر ننویسد، هیچ اتفاقی نمیافتد. قرارداد بهگونهای طراحی شده که پذیرش آن اختیاری و بیریسک باشد.
محتوای داخل تگ، طرح پیشفرض خودِ قالب است. تا وقتی هدری انتخاب نشده باشد همان رندر میشود؛ بهمحض انتخاب، جای آن را میگیرد. پس کافی است سربرگی که از قبل داشتهاید را داخل تگ بگذارید.
<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 هیچ چارچوبی رندر نمیشود. قالبی که اصلاً این تگ را ننویسد، هدر داینامیک نخواهد داشت و این یک انتخاب معتبر است.
| قرارداد | جا | کارش چیست |
|---|---|---|
ISiteLayoutPartCatalog | Core | فهرست هدرها و فوترها برای هر انتخابگری — بدون ارجاع به صفحهساز |
ISiteLayoutPolicyProvider | Core | پیشفرض سراسری سایت؛ برای جایگزینی کل سیاست |
IContentLayoutContext | Core | انتخاب همین درخواست؛ هر نوع محتوایی میتواند آن را اعلام کند |
ISiteLayoutResolver | Core | نتیجهٔ نهایی پس از ادغام سه سطح؛ همان چیزی که تگهلپر میخواند |
SiteLayoutCacheTags.Part(id) | Framework.Web | تگ کش مشترک بین رندرکننده و سرویسی که آن را باطل میکند |
یک نوع محتوای جدید (مثلاً «محصول» در یک افزونه) با یک خط، همین قابلیت را میگیرد؛ لازم نیست چیزی دربارهٔ هدرها بداند:
// پیش از رندر شدن Layout صدا زده میشود؛ MVC ابتدا View و سپس Layout را اجرا میکند.
contentLayout.SetChoices(
new SiteLayoutPartChoice(product.HeaderMode, product.HeaderPartId),
new SiteLayoutPartChoice(product.FooterMode, product.FooterPartId));
خروجی هدر از یک ViewComponent قابل بازنویسی میآید. برای تغییر مارکآپ آن، این فایل را در قالب خود بسازید:
themes/{Name}/Views/PageBuilder/LayoutPart/Default.cshtml
فصل ۳ · بخش ۴
مثل وردپرس میتوانید بگویید نشانی / چه چیزی را نشان دهد و کدام برگه، آرشیو مطالب را میزبانی کند. هر دو تنظیم در «قالب و لایهبندی» هستند.
| حالت صفحه اصلی | نتیجه |
|---|---|
| صفحهٔ پیشفرض قالب | نمای Home/Index قالب فعال. پیشفرض، و رفتار همهٔ سایتهای موجود. |
| یک برگهٔ ثابت | همان برگه در ریشه رندر میشود و در نشانی خودش هم در دسترس میماند. |
| یک فهرست | فهرستی که یک ماژول عرضه کرده است؛ بهصورت پیشفرض «آخرین مطالب». |
صفحهٔ مطالب دقیقاً مدل وردپرس است: نشانی آن برگه آرشیو مطالب را نشان میدهد، عنوان و نشانی از خودِ برگه گرفته میشود و محتوای برگه نمایش داده نمیشود. مسیر /posts هم به کار خود ادامه میدهد.
هر ماژول میتواند فهرست خودش را بهعنوان گزینهٔ صفحه اصلی عرضه کند. کافی است یک IFrontPageSource ثبت شود؛ نه مسیریابی تغییر میکند و نه صفحهٔ تنظیمات.
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 | بوم ویرایش؛ از قالب واقعی سایت رندر میشود |
| تب «برگه» در صفحهساز | انتخاب هدر و فوتر همان برگه، بدون خروج از ویرایشگر |
تغییرات داخل درخت ویجتها بهصورت قطعهای به بوم تزریق میشوند. اما هر چیزی که سرور رندر میکند — چارچوب صفحه، توکنهای طراحی، بوم خالی — بیرون از آن درخت است و بارگذاری دوبارهٔ بوم لازم دارد. این موارد آن را اجرا میکنند:
فصل ۴ · بخش ۱
ورکفلو یک فرایند دیداری است: مدیر گامها را روی بوم میچیند، مسیر میان آنها را مشخص میکند و بدون تغییر کد، تجربهای مانند ثبتنام را کنترل میکند.
هر ورکفلو از یک شروع، چند گام کاری و دستکم یک پایان تشکیل میشود. موتور فرایند فقط مسیری را اجرا میکند که شما با اتصالها ساختهاید. برای مثال، یک ثبتنام ساده چنین خوانده میشود:
بازدیدکننده وارد صفحهٔ ثبتنام میشود و اجرای تازه آغاز میگردد.
فرم نمایش داده میشود یا شمارهٔ موبایل با کد یکبارمصرف تأیید میگردد.
بر اساس نتیجه، حساب ساخته میشود، پیام فرستاده میشود یا کاربر به مسیر دیگری میرود.
فرایند با نتیجهای روشن مانند «حساب ساخته شد» یا «در انتظار تأیید» تمام میشود.
| مسیر | کاربرد |
|---|---|
/admin/workflows | ساخت، ویرایش، انتشار، غیرفعالسازی و حذف ورکفلوها |
/admin/workflows/runs | دیدن اجراهای واقعی، وضعیت آنها و تاریخچهٔ هر اجرا |
/admin/account/register | صفحهٔ واقعی ثبتنام؛ اگر حالت «فرایند طراحیشده» فعال باشد، ورکفلو در همین نشانی اجرا میشود |
/flow/{slug} | نشانی عمومی فرایندهایی که صفحهٔ اختصاصی ندارند؛ این فرایندها را هسته یا افزونه معرفی میکند |
فصل ۴ · بخش ۲
صفحهٔ طراح سه ستون اصلی و یک نوار فرمان دارد. اگر نقش هر قسمت را بدانید، ساخت فرایند شبیه چیدن چند کارت و وصلکردن آنهاست.
همهٔ گامهای قابل استفاده را گروهبندی میکند. نام ابزار را جستوجو کنید، سپس کارت آن را بکشید و روی بوم رها کنید. ابزارهای افزونهها نیز همینجا ظاهر میشوند.
گرهها و اتصالها اینجا قرار میگیرند. فضای خالی را بکشید تا بوم جابهجا شود؛ با چرخ ماوس بزرگنمایی کنید و با «اندازهٔ مناسب» کل نمودار را ببینید.
با انتخاب یک گام، عنوان، وضعیت، فیلدها و پیامهای اعتبارسنجی همان گام نمایش داده میشود. با انتخاب یک اتصال نیز مقصد آن قابل تغییر است.
برای دیدن راهنمای خودِ فرایند، روی فضای خالی بوم کلیک کنید. پنل تنظیمات، ورودیهای آماده مانند returnUrl و نتیجههای قابل قبول برای گام «پایان» را نشان میدهد.
فصل ۴ · بخش ۳
برای شروع لازم نیست نمودار را از صفر بسازید. ورکفلوی «ثبتنام کاربر» با یک نمونهٔ کامل و قابل اجرا ایجاد میشود؛ آن را بررسی، آزمایش و سپس شخصیسازی کنید.
از منوی مدیریت، «ورکفلوها ← طراحی فرایندها» را باز و روی «ورکفلو جدید» کلیک کنید.
«ثبتنام کاربر» را انتخاب کنید، نامی روشن مانند «ثبتنام اصلی سایت» بنویسید و «ایجاد و ویرایش» را بزنید.
مسیر پیشفرض از «شروع» به «فرم ثبتنام» و «ساخت حساب» میرود. خروجیهای ساخت حساب، مسیر موفق، در انتظار تأیید و ناموفق را جدا میکنند.
روی «فرم ثبتنام» کلیک کنید و فرم، عنوان دکمه و پیشوند متغیر را ببینید. روی «ساخت حساب» کلیک کنید و مطمئن شوید فیلدها از مقادیری مانند {{form.mobile}} خوانده میشوند.
برای نمونه، ابزار «ارسال پیامک» را میان مسیر موفق و پایان قرار دهید: خروجی «ساخته شد» را به پیامک و خروجی «ارسال شد» را به گام بعد وصل کنید.
ابتدا «ذخیره»، سپس «آزمایش» را بزنید. در آزمایش هیچ حساب، پیامک یا ایمیل واقعی ساخته و ارسال نمیشود.
وقتی خطای ساختاری ندارید، «انتشار» را بزنید. سپس در «تنظیمات ← ورود و ثبتنام» حالت «فرایند طراحیشده» را فعال و صفحهٔ ثبتنام را در یک پنجرهٔ ناشناس امتحان کنید.
فصل ۴ · بخش ۴
هر اتصال میگوید «پس از این نتیجه، کدام گام اجرا شود». جهت نمودار RTL است: ورودی گام در سمت راست و خروجیهای آن در سمت چپ کارت قرار دارند.
| کار | روش انجام |
|---|---|
| تغییر مقصد | روی خط اتصال کلیک کنید و در پنل تنظیمات، مقصد تازه را انتخاب کنید؛ یا همان خروجی را به مقصد جدید بکشید. |
| حذف اتصال | خط را انتخاب و Delete بزنید؛ یا راستکلیک و «حذف اتصال» را انتخاب کنید. |
| قطع همهٔ مسیرهای یک گام | روی گام راستکلیک و «قطع اتصالها» را انتخاب کنید. |
| ساخت دو شاخه | از هر خروجیِ گام شرط یک اتصال مستقل بسازید: «درست» به مسیر قبول و «نادرست» به مسیر جایگزین. |
| خروجی پویا | تنظیمات گام را کامل کنید و لحظهای منتظر بررسی سرور بمانید؛ خروجیهایی که از تنظیمات ساخته میشوند خودکار روی کارت تازه میشوند. |
هر خروجی فقط یک مقصد دارد. اگر همان خروجی را دوباره وصل کنید، اتصال قبلی با مقصد جدید جایگزین میشود. برای فرستادن اجرا به دو مسیر متفاوت، باید از دو خروجی جدا مانند «درست/نادرست» استفاده کنید؛ یک خروجی عادی بهصورت همزمان دو مقصد ندارد.
فصل ۴ · بخش ۵
فهرست دقیق ابزارها به قابلیتهای نصبشده و دسترسی مدیر بستگی دارد. ابزارهای پایه و ابزارهای فعلی پلتفرم در جدول زیر آمدهاند.
| گروه و ابزار | چه کاری انجام میدهد | نکتهٔ کاربردی |
|---|---|---|
| شروع | نقطهٔ ورود فرایند است. | هر نمودار باید یک شروع معتبر داشته باشد؛ آن را داخل Fragment قرار ندهید. |
| پایان | اجرا را با یک نتیجهٔ مشخص تمام میکند. | کلید یکی از «پایانهای شناختهشده» همان فرایند را وارد کنید؛ مانند registered یا pending. |
| شرط | دو مقدار را مقایسه و مسیر درست یا نادرست را انتخاب میکند. | برای خالیبودن، برابری، شاملبودن و مقایسهٔ عددی مناسب است. |
| تعیین متغیر | یک مقدار ثابت یا ترکیبی را برای گامهای بعد نگه میدارد. | برای دادهٔ محرمانه گزینهٔ «مقدار حساس است» را همان ابتدا فعال کنید. |
| یادداشت | یک توضیح در تاریخچهٔ اجرای مدیر ثبت میکند. | برای فهمیدن تصمیمهای مهم مفید است؛ رمز، کد یا اطلاعات حساس را در متن یادداشت ننویسید. |
| انتظار | اجرا را تا رسیدن پاسخ بیرونی متوقف میکند. | دلیل انتظار و نام متغیر پاسخ را روشن بنویسید؛ برای تأیید دستی یا یک رویداد بیرونی مناسب است. |
| تأخیر | اجرا را چند دقیقه، ساعت یا روز متوقف و سپس خودکار ادامه میدهد. | برای یادآوری و پیگیری مناسب است و پس از راهاندازی دوبارهٔ سایت نیز ادامه پیدا میکند. |
| جستوجو در دادهها | یک شناسه را در منبع ثبتشده پیدا و نتیجه را در متغیر ذخیره میکند. | دو خروجی «پیدا شد» و «پیدا نشد» دارد؛ نتیجه شامل مقدار، عنوان و والد است. |
| فرم | یک فرمِ ساختهشده در فرمساز را نشان میدهد و پاسخها را ذخیره میکند. | با پیشوند form، فیلد موبایل به صورت {{form.mobile}} در دسترس است. |
| تأیید شماره با کد | کد یکبارمصرف میفرستد و منتظر ورود کد میماند. | مسیرهای «تأیید شد»، «ارسال ناموفق» و «تغییر شماره» را جدا وصل کنید. |
| ساخت حساب | حساب کاربری را با همهٔ سیاستهای امنیتی ثبتنام سایت میسازد. | سه مسیر «ساخته شد»، «در انتظار تأیید» و «ناموفق» دارد. |
| ورود به حساب | کاربر ساختهشده را وارد میکند و سیاست عامل دوم را رعایت میکند. | برای «نیازمند عامل دوم» و «ناموفق» نیز مقصد مشخص بسازید. |
| ارسال ایمیل | قالب اعلان را رندر و ایمیل را برای ارسال در صف قرار میدهد. | قالب را از فهرست انتخاب و مسیر ناموفق را مدیریت کنید. |
| ارسال پیامک | قالب پیامک را برای گیرنده در صف ارسال میگذارد. | در آزمایش پیام واقعی فرستاده نمیشود؛ نتیجهٔ ارسال واقعی در جزئیات اجرا دیده میشود. |
فصل ۴ · بخش ۶
متغیر ظرفی نامدار برای داده است. یک گام مقدار را میسازد و گام بعد با نوشتن {{نام}} آن را میخواند؛ پنل تنظیمات برای بیشتر فیلدها انتخابگر متغیر دارد.
پیش از شروع آماده است؛ در ثبتنام، returnUrl مسیر بازگشت پس از موفقیت را نگه میدارد.
ابزارها مقدارهایی مانند شمارهٔ تأییدشده، شناسهٔ کاربر یا نتیجهٔ جستوجو را تولید میکنند.
مدیر آن را از دکمهٔ { } بالای بوم میسازد و نوع، مقدار اولیه و حساسبودن را تعیین میکند.
{{form.mobile}}
{{form.firstName}} عزیز، خوش آمدید
{{lookup.label}}
/my?return={{returnUrl}}
اگر کل فیلد فقط یک توکن باشد، مقدار اصلی آن ــ حتی عدد، بله/خیر یا شیء JSON ــ حفظ میشود. اگر توکن داخل یک جمله باشد، مقدار به متن تبدیل و در همان جای جمله قرار میگیرد. برای جلوگیری از غلط تایپی، از فهرست «درج متغیر…» کنار فیلد استفاده کنید.
{ } کلیک کنید؛ عدد کنار آن تعداد متغیرهای اعلامشده را نشان میدهد.profile.segment و یک عنوان قابل فهم بنویسید.| نوع فیلد در تنظیمات | نحوهٔ استفاده |
|---|---|
| عبارت و مسیر | متن ثابت یا متغیر درج کنید؛ پیشنمایش عبارت کمک میکند نتیجه را قبل از اجرا ببینید. |
| انتخابگر | فرم، منبع داده، قالب ایمیل/پیامک، نقش، مجوز یا مسیر را از فهرست انتخاب کنید. |
| مدت | مقدار را با واحد دقیقه، ساعت یا روز وارد کنید؛ طراح آن را به مقدار استاندارد تبدیل میکند. |
| نام متغیر | نام مقصدی است که ابزار نتیجه را در آن مینویسد؛ پیشنهادهای موجود از غلط تایپی جلوگیری میکنند. |
فصل ۴ · بخش ۷
چرخهٔ امن کار این است: نمودار را کامل کنید، پیامهای بررسی را بخوانید، پیشنویس را ذخیره کنید، اجرای آزمایشی بگیرید و در پایان انتشار دهید.
| عمل | اثر | چه زمانی انجام شود |
|---|---|---|
| بررسی خودکار | پس از هر تغییر، خطاها، هشدارها و خروجیهای پویا را از سرور تازه میکند. | همیشه فعال است؛ روی نشان وضعیت کلیک کنید. |
| ذخیره | همین پیشنویس را نگه میدارد؛ حتی نمودار نیمهکاره و دارای هشدار قابل ذخیره است. | مرتب و پیش از خروج؛ میانبر Ctrl+S. |
| آزمایش | فرایند را با ورودی JSON اجرا، اثرهای بیرونی را شبیهسازی و Timeline تولید میکند. | پس از هر تغییر مهم و پیش از انتشار. |
| انتشار | نسخه را ثابت و فعال میکند و یک پیشنویس با شمارهٔ بعدی میسازد. | پس از رفع خطاها، بررسی هشدارها و تأیید نتیجهٔ آزمایش. |
خطا یعنی نمودار از نظر ساختاری قابل اجرا نیست؛ مانند نبودن شروع، ابزار ناشناخته یا اتصال به گام حذفشده. انتشار تا رفع آن ممکن نیست. هشدار دربارهٔ ریسک یا مسیر ناقص است؛ مانند گام دور از دسترس یا خروجی باز. هشدار جلوی انتشار را نمیگیرد، اما باید آگاهانه پذیرفته شود.
{ } شروع و پایان یابد.{
"returnUrl": "/my"
}
فصل ۴ · بخش ۸
برای نمودارهای بزرگ، طراح امکانات چیدمان، بازاستفاده، انتقال و کنترل نسخه دارد. این ابزارها سرعت کار را بالا میبرند، ولی هیچکدام بدون ذخیره یا انتشار، نسخهٔ فعال را تغییر نمیدهند.
Shift را نگه دارید و روی فضای خالی یک کادر بکشید؛ یا با Ctrl روی گامها کلیک کنید. نوار شناور تعداد گامهای انتخابشده را نشان میدهد.
گامها را از چپ، مرکز، راست، بالا یا پایین همتراز کنید. برای سه گام یا بیشتر، فاصلهٔ افقی یا عمودی را یکنواخت کنید.
تا ۵۰ تغییر اخیر قابل بازگردانی است. کپی/چسباندن و تکرار گروهی، اتصالهای داخلیِ انتخاب را نیز حفظ میکنند.
| امکان | کاربرد و محدودیت |
|---|---|
| مرتبسازی خودکار | نمودار درهم را از راست به چپ و بر اساس فاصله از شروع مرتب میکند. موقعیتها بعداً همچنان قابل ویرایشاند. |
| رفتن به گام | نام گام را از فهرست بالای بوم انتخاب کنید تا بدون جستوجوی دستی در مرکز دید قرار گیرد. |
| حالت تمرکز | هر دو پنل کناری را پنهان میکند. نمایش هر پنل جداگانه نیز ممکن است و انتخاب شما در همان مرورگر حفظ میشود. |
| خروجی JSON | گامها، اتصالها، متغیرها و تنظیمات نسخهٔ فعلی را در فایل .workflow.json نگه میدارد. فایل ممکن است مقدارهای اولیه را داشته باشد؛ آن را مانند دادهٔ مدیریتی محافظت کنید. |
| ورود JSON | فایل حداکثر یک مگابایت را پس از بررسی نوع فرایند، اندازه، ابزارهای نصبشده و سلامت اتصالها جایگزین پیشنویس میکند. با بازگردانی قابل برگشت است. |
| Fragment | حداکثر ۵۰ گام انتخابشده و اتصالهای داخلی را بهعنوان قطعهٔ قابل بازاستفاده ذخیره میکند؛ گام شروع داخل آن قرار نمیگیرد. |
| مقایسهٔ نسخهها | پیشنویس را با یکی از ۵۰ نسخهٔ اخیر مقایسه و گام افزوده، حذفشده، تغییرکرده، اتصال و متغیر تغییرکرده را گزارش میکند. |
| بارگذاری نسخهٔ قدیمی | نمودار انتخابشده را فقط روی پیشنویس میآورد؛ نسخهٔ منتشرشده تغییر نمیکند تا شما ذخیره و انتشار تازه انجام دهید. |
| میانبر | کار |
|---|---|
Ctrl+S | ذخیرهٔ پیشنویس |
Ctrl+Z / Ctrl+Y | بازگردانی / انجام دوباره |
Ctrl+C / Ctrl+V | کپی / چسباندن گامهای انتخابشده با اتصالهای داخلی |
Ctrl+D | تکرار انتخاب |
Ctrl+A | انتخاب همهٔ گامها |
Delete | حذف گامها یا اتصال انتخابشده |
/ | رفتن به جستوجوی ابزارها |
F | جا دادن کل نمودار در بوم |
| کلیدهای جهت | جابهجایی دقیق انتخاب؛ همراه Shift با گام بزرگتر |
فصل ۴ · بخش ۹
بعد از انتشار، بخش «اجراها» پاسخ میدهد چه کسی در کدام گام مانده، فرایند چگونه تمام شده و عملیاتهایی مانند پیامک با چه وضعیتی تحویل شدهاند.
registered ثبت شده است.جزئیات هر اجرا، نسخهٔ ورکفلو، زمان شروع و پایان، گام فعلی، نتیجه و تاریخچهٔ گامها را با مدت هر مرحله نشان میدهد. برای حفاظت از اطلاعات شخصی، متغیرهای کامل اجرا در این صفحه نمایش داده نمیشوند. اگر گام دارای اثر بیرونی باشد، بخش «عملیاتهای پسزمینه» وضعیت در انتظار، در حال ارسال، ارسالشده یا ناموفق، تعداد تلاش و آخرین خطا را جدا نشان میدهد.
| مجوز | اختیار | برای چه نقشی |
|---|---|---|
admin.workflows.view | دیدن فهرست ورکفلو و تاریخچهٔ اجراهای پایانیافته | پشتیبانی و ناظر فرایند |
admin.workflows.manage | ساخت، طراحی، ذخیره، حذف و اجرای آزمایشی | طراح فرایند |
admin.workflows.publish | فعالکردن نسخه برای کاربران یا غیرفعالسازی آن | مدیر انتشار |
admin.workflows.runs | دیدن اجرای زنده و لغو اجرای در حال اجرا یا منتظر | اپراتور مورد اعتماد |
| نشانه | علت محتمل | راهحل |
|---|---|---|
| دو گام وصل نمیشوند | کشیدن از بدنهٔ کارت یا رهاکردن پیش از برجستهشدن مقصد | از نقطهٔ خروجی رنگیِ سمت چپ مبدأ بکشید و روی ورودی یا بدنهٔ مقصدِ برجسته رها کنید. |
| اتصال قبلی ناپدید شد | همان خروجی به مقصد تازه وصل شده است | هر خروجی فقط یک مقصد دارد؛ برای دو مسیر از گام شرط یا خروجیهای جدا استفاده کنید. |
| خروجیهای مورد انتظار دیده نمیشوند | تنظیم گام کامل نشده یا خروجی پویا هنوز اعتبارسنجی نشده است | تنظیم را کامل کنید، بیرون فیلد کلیک کنید، لحظهای صبر و فهرست بررسیها را باز کنید. |
| ابزار قرمز یا ناشناخته است | افزونهٔ صاحب ابزار غیرفعال یا حذف شده است | افزونه را برگردانید یا گام را با ابزار نصبشده جایگزین کنید. |
| ذخیره با تداخل رد میشود | پیشنویس در تب یا نشست دیگری زودتر ذخیره شده است | در صورت نیاز JSON بگیرید، صفحه را تازه کنید و تغییر را روی آخرین نسخه اعمال کنید. |
| آزمایش روی «در انتظار» میماند | به فرم، کد تأیید، انتظار یا رویداد زماندار رسیده است | Timeline و «در انتظار چه چیزی» را بخوانید؛ این وضعیت برای گامهای تعاملی طبیعی است. |
| پیامک یا ایمیل آزمایشی نرسید | اثرهای بیرونی در آزمایش عمداً شبیهسازی میشوند | برای آزمون واقعی، نسخه را با گیرندهٔ کنترلشده منتشر و وضعیت عملیات پسزمینه را بررسی کنید. |
| تغییر برای بازدیدکننده دیده نمیشود | فقط ذخیره شده، منتشر نشده یا حالت ثبتنام هنوز استاندارد است | انتشار را انجام دهید و برای ثبتنام، «فرایند طراحیشده» را در تنظیمات ورود و ثبتنام فعال کنید. |
| مقدار در گزارش پوشانده شده است | متغیر حساس است | این رفتار امنیتی صحیح است؛ برای رفع اشکال از مسیر اجرا و پیامهای غیرحساس استفاده کنید. |
فصل ۰ · بخش ۱
هر فصل یک گروه بازشونده در منو دارد و هر موضوع داخل آن یک <section> مستقل است. با این الگو میتوان فصل و بخش تازه را بدون تغییر در استایل صفحه اضافه کرد.
nav-chapter با عنوان و شمارهی فصل در محدودهی DOC-NAV بسازید.section.doc-section با id انگلیسی و یکتا بسازید.۳.۱ داخل زیرمنوی همان فصل قرار دهید.code-shell استفاده کنید تا متن همیشه LTR و مناسب کپی باشد.figure.media-frame استفاده و زیرنویس کوتاه اضافه کنید.<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 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>
<figure class="media-frame">
<img src="images/request-flow.webp"
alt="مسیر درخواست از Host تا PlatformDbContext"
loading="lazy">
<figcaption>شکل ۲ — مسیر پردازش یک درخواست HTTP.</figcaption>
</figure>