# جریان کاربری — تسک ۱۱: پنل اشتراکی ## جریان مشاهده پنل‌ها و خرید ``` کاربر وارد صفحه اشتراک می‌شود │ ▼ GET /api/v1/subscription/my → نمایش پنل فعلی + تاریخ انقضا (شمسی) + days_remaining → اگر used_trial=false و trial_enabled=true → بنر تریال نمایش داده می‌شود │ ▼ GET /api/v1/subscription/plans → جدول مقایسه پنل‌ها (free | basic | professional) → هر پنل: لیست دوره‌ها با قیمت — دروه تریال جدا نمایش داده می‌شود │ ├─► کاربر «تریال» انتخاب می‌کند: │ │ │ ▼ │ POST /api/v1/subscription/trial │ ├─► 200: فعال شد → صفحه refresh │ └─► 400: قبلاً استفاده شده → toast خطا │ └─► کاربر یک دوره پولی انتخاب می‌کند: │ ▼ POST /api/v1/subscription-payment (موجود) { period_uuid, gateway: 'mellat' } │ ▼ redirect به gateway بانک │ ▼ GET|POST /api/v1/subscription-payment/callback/{gateway} │ ▼ SubscriptionService::createFromPayment() → ClinicSubscription ساخته می‌شود │ ▼ redirect به /admin/subscription?success=1 ``` ## جریان تمدید اشتراک ``` اشتراک ۶ ماهه فعال است (expires_at = آینده) │ ▼ کاربر دوره جدید ۶ ماهه انتخاب می‌کند و پرداخت می‌کند │ ▼ calculateExpiresAt(): base = max(expires_at_فعلی, now) ← از تاریخ انقضا (نه الان) new_expires = base + 6 × 30 × 86400 │ ▼ اشتراک ۶ ماه دیگر تمدید می‌شود بدون اتلاف زمان باقی‌مانده ``` ## جریان gate check در تسک‌های بعدی ``` کاربر Free تلاش می‌کند پرونده بیمار بسازد │ ▼ POST /api/v1/patient │ ▼ PatientController::create(): $hasFeature = $subscriptionService->hasFeature($entityType, $entityId, 'patient_records') │ ├─► false → 403 ERR_SUBSCRIPTION_REQUIRED │ { "errors": [{ "code": "ERR_SUBSCRIPTION_REQUIRED", │ "message": "این قابلیت نیاز به پنل Basic یا بالاتر دارد" }] } │ └─► true → ادامه پردازش ``` ## جریان مدیریت پنل‌ها توسط ادمین ``` ادمین وارد صفحه مدیریت اشتراک می‌شود │ ├─► تب «پنل‌ها»: │ GET /api/v1/admin/subscription/plans │ → جدول پنل‌ها با دوره‌ها و قیمت‌ها │ → PATCH /api/v1/admin/subscription/period/{uuid} ← ویرایش inline قیمت │ → POST /api/v1/admin/subscription/period ← افزودن دوره جدید │ └─► تب «گزارش»: GET /api/v1/admin/subscription/report?from=UNIX&to=UNIX → تعداد خریدها + مجموع درآمد + تعداد تریال‌ها → breakdown بر اساس plan و period ``` ## هشدار انقضا (frontend) ``` در هر بار لود صفحه: اگر days_remaining <= 7 و expires_at != null: → نمایش banner هشدار: «اشتراک شما X روز دیگر منقضی می‌شود — تمدید کنید» ``` ## نمایش در Frontend (SubscriptionPage.tsx) ``` ┌─────────────────────────────────────────────────────┐ │ 🎁 یک ماه تریال رایگان — فعال‌سازی │ ← فقط اگر used_trial=false ├─────────────────────────────────────────────────────┤ │ پنل فعلی: Basic | انقضا: ۱۴۰۵/۰۶/۲۳ | ۴۲ روز │ ├───────────┬──────────────────┬─────────────────────┤ │ Free │ Basic ★ │ Professional │ │ رایگان │ پرونده بیمار ✅ │ پرونده بیمار ✅ │ │ ۱ منشی │ سرویس‌ها ✅ │ سرویس‌ها ✅ │ │ │ ۲ منشی │ ۵ منشی │ │ │ ┌──────────┐ │ │ │ │ │ ۱ ماهه │ │ [انتخاب دوره ▼] │ │ │ │ ۲۵۰,۰۰۰ │ │ │ │ │ │ ۶ ماهه │ │ │ │ │ │ ۱,۲۰۰,۰۰۰│ │ │ │ │ └──────────┘ │ │ │ │ [خرید اشتراک] │ [خرید اشتراک] │ └───────────┴──────────────────┴─────────────────────┘ ```