# تسک ۱۰ — فرم ساخت قانون و محیط آزمایش **فاز:** ۲ (قوانین) · **وابستگی:** ۰۹ · **زمان:** ۱۰-۱۲ ساعت --- ## هدف مستند بند ۱۷، ریسک دوم: «کاربر غیرفنی نمی‌تواند قانون درست تعریف کند → قانون‌های اشتباه، رفتار عجیب». راه‌حل مستند: **فرم آماده، الگوهای از پیش تعریف‌شده، آزمایش اجباری قبل از فعال شدن.** بدون این تسک، تسک ۰۹ یک API قدرتمند است که هیچ‌کس نمی‌تواند از آن استفادهٔ درست کند. ## دامنه **هست:** - فرم ساخت قانون که از `GET /api/v1/policy-schema` ساخته می‌شود (نه hard-code در فرانت) - الگوهای آماده (`policy templates`) — کاربر الگو را انتخاب و مقدار پر می‌کند - محیط آزمایش (`dry-run`): اجرای قانون روی داده واقعی بدون ثبت هیچ چیز - **آزمایش اجباری**: `activate` تا وقتی یک اجرای آزمایشی موفق ثبت نشده، رد می‌شود - نمایش تاریخچهٔ نسخه‌ها با diff **نیست:** موتور قانون (تسک ۰۹). ## Endpoint ها | متد | مسیر | توضیح | |---|---|---| | POST | `/api/v1/policy/{uuid}/simulate` | اجرای آزمایشی روی نوبت‌های واقعی گذشته | | GET | `/api/v1/policy-templates` | الگوهای آماده | `POST /policy/{uuid}/activate` (تسک ۰۹) یک شرط جدید می‌گیرد: وجود یک `simulate` موفق برای نسخهٔ جاری. ## معیار پذیرش - ✅ موفق: کاربر الگوی «حداقل فاصله بین جلسات» را انتخاب می‌کند، سرویس و تعداد روز را پر می‌کند، `simulate` می‌زند → گزارشی از ۵۰ نوبت اخیر: چند تا تحت تأثیر قرار می‌گرفتند و دقیقاً چه تغییری می‌کردند. - ✅ موفق: `simulate` هیچ ردیفی در دیتابیس نمی‌نویسد (به‌جز `policy_simulation_runs`). تست باید تعداد ردیف‌های `appointments`, `price_snapshots`, `resource_occupancy` را قبل و بعد مقایسه کند. - ✅ موفق: بعد از `simulate` موفق، `activate` کار می‌کند. - ✅ موفق: فرم ساخت قانون بدون هیچ تغییر کد فرانت، فیلد جدیدی که به `FieldRegistry` اضافه شود را نشان می‌دهد. - ❌ خطا: `activate` بدون `simulate` → `422` با پیام «ابتدا قانون را آزمایش کنید». - ❌ خطا: `activate` بعد از تغییر محتوای قانون (نسخهٔ جدید) → `simulate` قبلی معتبر نیست → `422`. - ⚠️ مرزی: محیطی که هیچ نوبت گذشته‌ای ندارد → `simulate` با گزارش خالی و `warning: 'داده‌ای برای آزمایش نیست'` موفق شود (وگرنه کلینیک جدید هرگز نمی‌تواند قانون فعال کند). - ⚠️ مرزی: قانون `deny` که همهٔ ۵۰ نوبت را رد می‌کند → `simulate` موفق ولی با `severity: 'high'` و پیام «این قانون همهٔ نوبت‌های نمونه را رد می‌کند». - ⚠️ مرزی: `simulate` روی قانون دستهٔ `pricing` → تفاوت مبلغ per نوبت نمایش داده شود. ## خروجی - `src/Policy/Simulation/` - `assets/admin/pages/PoliciesPage.tsx` + `PolicyFormPage.tsx` + `PolicySimulationPage.tsx` - `docs/api/policy.md` به‌روزرسانی